1 /* 2 * PROJECT: ReactOS Spooler API 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Functions related to Printers and printing 5 * COPYRIGHT: Copyright 2015-2018 Colin Finck (colin@reactos.org) 6 */ 7 8 #include "precomp.h" 9 #include <marshalling/printers.h> 10 #include <marshalling/printerdrivers.h> 11 #include <strsafe.h> 12 13 // Local Constants 14 15 /** And the award for the most confusingly named setting goes to "Device", for storing the default printer of the current user. 16 Ok, I admit that this has historical reasons. It's still not straightforward in any way though! */ 17 static const WCHAR wszWindowsKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"; 18 static const WCHAR wszDeviceValue[] = L"Device"; 19 20 static DWORD 21 _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB_INFO_1W pAddJobInfo1) 22 { 23 DWORD cbNeeded; 24 DWORD dwErrorCode; 25 PJOB_INFO_1W pJobInfo1 = NULL; 26 27 // Create the spool file. 28 pHandle->hSPLFile = CreateFileW(pAddJobInfo1->Path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); 29 if (pHandle->hSPLFile == INVALID_HANDLE_VALUE) 30 { 31 dwErrorCode = GetLastError(); 32 ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1->Path, dwErrorCode); 33 goto Cleanup; 34 } 35 36 // Get the size of the job information. 37 GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded); 38 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 39 { 40 dwErrorCode = GetLastError(); 41 ERR("GetJobW failed with error %lu!\n", dwErrorCode); 42 goto Cleanup; 43 } 44 45 // Allocate enough memory for the returned job information. 46 pJobInfo1 = HeapAlloc(hProcessHeap, 0, cbNeeded); 47 if (!pJobInfo1) 48 { 49 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 50 ERR("HeapAlloc failed!\n"); 51 goto Cleanup; 52 } 53 54 // Get the job information. 55 if (!GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, cbNeeded, &cbNeeded)) 56 { 57 dwErrorCode = GetLastError(); 58 ERR("GetJobW failed with error %lu!\n", dwErrorCode); 59 goto Cleanup; 60 } 61 62 // Add our document information. 63 if (pDocInfo1->pDatatype) 64 pJobInfo1->pDatatype = pDocInfo1->pDatatype; 65 66 pJobInfo1->pDocument = pDocInfo1->pDocName; 67 68 // Set the new job information. 69 if (!SetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0)) 70 { 71 dwErrorCode = GetLastError(); 72 ERR("SetJobW failed with error %lu!\n", dwErrorCode); 73 goto Cleanup; 74 } 75 76 // We were successful! 77 pHandle->dwJobID = pAddJobInfo1->JobId; 78 dwErrorCode = ERROR_SUCCESS; 79 80 Cleanup: 81 if (pJobInfo1) 82 HeapFree(hProcessHeap, 0, pJobInfo1); 83 84 return dwErrorCode; 85 } 86 87 static DWORD 88 _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1) 89 { 90 DWORD dwErrorCode; 91 WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer; 92 93 DocInfoContainer.Level = 1; 94 DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1; 95 96 RpcTryExcept 97 { 98 dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer, &pHandle->dwJobID); 99 } 100 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 101 { 102 dwErrorCode = RpcExceptionCode(); 103 ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode); 104 } 105 RpcEndExcept; 106 107 return dwErrorCode; 108 } 109 110 BOOL WINAPI 111 AbortPrinter(HANDLE hPrinter) 112 { 113 TRACE("AbortPrinter(%p)\n", hPrinter); 114 UNIMPLEMENTED; 115 return FALSE; 116 } 117 118 HANDLE WINAPI 119 AddPrinterA(PSTR pName, DWORD Level, PBYTE pPrinter) 120 { 121 TRACE("AddPrinterA(%s, %lu, %p)\n", pName, Level, pPrinter); 122 UNIMPLEMENTED; 123 return NULL; 124 } 125 126 HANDLE WINAPI 127 AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter) 128 { 129 TRACE("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter); 130 UNIMPLEMENTED; 131 return NULL; 132 } 133 134 BOOL WINAPI 135 ClosePrinter(HANDLE hPrinter) 136 { 137 DWORD dwErrorCode; 138 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 139 140 TRACE("ClosePrinter(%p)\n", hPrinter); 141 142 // Sanity checks. 143 if (!pHandle) 144 { 145 dwErrorCode = ERROR_INVALID_HANDLE; 146 goto Cleanup; 147 } 148 149 // Do the RPC call. 150 RpcTryExcept 151 { 152 dwErrorCode = _RpcClosePrinter(&pHandle->hPrinter); 153 } 154 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 155 { 156 dwErrorCode = RpcExceptionCode(); 157 ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode); 158 } 159 RpcEndExcept; 160 161 // Close any open file handle. 162 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE) 163 CloseHandle(pHandle->hSPLFile); 164 165 // Free the memory for the handle. 166 HeapFree(hProcessHeap, 0, pHandle); 167 168 Cleanup: 169 SetLastError(dwErrorCode); 170 return (dwErrorCode == ERROR_SUCCESS); 171 } 172 173 BOOL WINAPI 174 DeletePrinter(HANDLE hPrinter) 175 { 176 TRACE("DeletePrinter(%p)\n", hPrinter); 177 UNIMPLEMENTED; 178 return FALSE; 179 } 180 181 DWORD WINAPI 182 DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode) 183 { 184 TRACE("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode); 185 UNIMPLEMENTED; 186 return 0; 187 } 188 189 DWORD WINAPI 190 DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode) 191 { 192 TRACE("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode); 193 UNIMPLEMENTED; 194 return 0; 195 } 196 197 INT WINAPI 198 DocumentEvent( HANDLE hPrinter, HDC hdc, int iEsc, ULONG cbIn, PVOID pvIn, ULONG cbOut, PVOID pvOut) 199 { 200 TRACE("DocumentEvent(%p, %p, %lu, %lu, %p, %lu, %p)\n", hPrinter, hdc, iEsc, cbIn, pvIn, cbOut, pvOut); 201 UNIMPLEMENTED; 202 return DOCUMENTEVENT_UNSUPPORTED; 203 } 204 205 LONG WINAPI 206 DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode) 207 { 208 PWSTR pwszDeviceName = NULL; 209 PDEVMODEW pdmwInput = NULL; 210 PDEVMODEW pdmwOutput = NULL; 211 BOOL bReturnValue = -1; 212 DWORD cch; 213 214 TRACE("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode); 215 216 if (pDeviceName) 217 { 218 // Convert pName to a Unicode string pwszDeviceName. 219 cch = strlen(pDeviceName); 220 221 pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 222 if (!pwszDeviceName) 223 { 224 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 225 ERR("HeapAlloc failed!\n"); 226 goto Cleanup; 227 } 228 229 MultiByteToWideChar(CP_ACP, 0, pDeviceName, -1, pwszDeviceName, cch + 1); 230 } 231 232 if (pDevModeInput) 233 { 234 // Create working buffer for input to DocumentPropertiesW. 235 pdmwInput = HeapAlloc(hProcessHeap, 0, sizeof(DEVMODEW)); 236 if (!pdmwInput) 237 { 238 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 239 ERR("HeapAlloc failed!\n"); 240 goto Cleanup; 241 } 242 RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput, pdmwInput); 243 } 244 245 if (pDevModeOutput) 246 { 247 // Create working buffer for output from DocumentPropertiesW. 248 pdmwOutput = HeapAlloc(hProcessHeap, 0, sizeof(DEVMODEW)); 249 if (!pdmwOutput) 250 { 251 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 252 ERR("HeapAlloc failed!\n"); 253 goto Cleanup; 254 } 255 } 256 257 bReturnValue = DocumentPropertiesW(hWnd, hPrinter, pwszDeviceName, pdmwOutput, pdmwInput, fMode); 258 TRACE("bReturnValue from DocumentPropertiesW is '%ld'.\n", bReturnValue); 259 260 if (pwszDeviceName) 261 { 262 HeapFree(hProcessHeap, 0, pwszDeviceName); 263 } 264 265 if (bReturnValue < 0) 266 { 267 TRACE("DocumentPropertiesW failed!\n"); 268 goto Cleanup; 269 } 270 271 if (pdmwOutput) 272 { 273 RosConvertUnicodeDevModeToAnsiDevmode(pdmwOutput, pDevModeOutput); 274 } 275 276 Cleanup: 277 if(pwszDeviceName) 278 HeapFree(hProcessHeap, 0, pwszDeviceName); 279 280 if (pdmwInput) 281 HeapFree(hProcessHeap, 0, pdmwInput); 282 283 if (pdmwOutput) 284 HeapFree(hProcessHeap, 0, pdmwOutput); 285 286 return bReturnValue; 287 } 288 289 static PRINTER_INFO_9W * get_devmodeW(HANDLE hprn) 290 { 291 PRINTER_INFO_9W *pi9 = NULL; 292 DWORD needed = 0; 293 BOOL res; 294 295 res = GetPrinterW(hprn, 9, NULL, 0, &needed); 296 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) 297 { 298 pi9 = HeapAlloc(hProcessHeap, 0, needed); 299 res = GetPrinterW(hprn, 9, (LPBYTE)pi9, needed, &needed); 300 } 301 302 if (res) 303 return pi9; 304 305 ERR("GetPrinterW failed with %u\n", GetLastError()); 306 HeapFree(hProcessHeap, 0, pi9); 307 return NULL; 308 } 309 310 LONG WINAPI 311 DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode) 312 { 313 HANDLE hUseHandle = NULL; 314 PRINTER_INFO_9W *pi9 = NULL; 315 LONG Result = -1, Length; 316 317 TRACE("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode); 318 if (hPrinter) 319 { 320 hUseHandle = hPrinter; 321 } 322 else if (!OpenPrinterW(pDeviceName, &hUseHandle, NULL)) 323 { 324 ERR("No handle, and no usable printer name passed in\n"); 325 return -1; 326 } 327 328 pi9 = get_devmodeW(hUseHandle); 329 330 if (pi9) 331 { 332 Length = pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra; 333 // See wineps.drv PSDRV_ExtDeviceMode 334 if (fMode) 335 { 336 Result = 1; /* IDOK */ 337 338 if (fMode & DM_IN_BUFFER) 339 { 340 FIXME("Merge pDevModeInput with pi9, write back to driver!\n"); 341 // See wineps.drv PSDRV_MergeDevmodes 342 } 343 344 if (fMode & DM_IN_PROMPT) 345 { 346 FIXME("Show property sheet!\n"); 347 Result = 2; /* IDCANCEL */ 348 } 349 350 if (fMode & (DM_OUT_BUFFER | DM_OUT_DEFAULT)) 351 { 352 if (pDevModeOutput) 353 { 354 memcpy(pDevModeOutput, pi9->pDevMode, pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra); 355 } 356 else 357 { 358 ERR("No pDevModeOutput\n"); 359 Result = -1; 360 } 361 } 362 } 363 else 364 { 365 Result = Length; 366 } 367 368 HeapFree(hProcessHeap, 0, pi9); 369 } 370 371 if (hUseHandle && !hPrinter) 372 ClosePrinter(hUseHandle); 373 return Result; 374 } 375 376 BOOL WINAPI 377 EndDocPrinter(HANDLE hPrinter) 378 { 379 DWORD dwErrorCode; 380 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 381 382 TRACE("EndDocPrinter(%p)\n", hPrinter); 383 384 // Sanity checks. 385 if (!pHandle) 386 { 387 dwErrorCode = ERROR_INVALID_HANDLE; 388 goto Cleanup; 389 } 390 391 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE) 392 { 393 // For spooled jobs, the document is finished by calling _RpcScheduleJob. 394 RpcTryExcept 395 { 396 dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID); 397 } 398 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 399 { 400 dwErrorCode = RpcExceptionCode(); 401 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode); 402 } 403 RpcEndExcept; 404 405 // Close the spool file handle. 406 CloseHandle(pHandle->hSPLFile); 407 } 408 else 409 { 410 // In all other cases, just call _RpcEndDocPrinter. 411 RpcTryExcept 412 { 413 dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter); 414 } 415 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 416 { 417 dwErrorCode = RpcExceptionCode(); 418 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode); 419 } 420 RpcEndExcept; 421 } 422 423 // A new document can now be started again. 424 pHandle->bStartedDoc = FALSE; 425 426 Cleanup: 427 SetLastError(dwErrorCode); 428 return (dwErrorCode == ERROR_SUCCESS); 429 } 430 431 BOOL WINAPI 432 EndPagePrinter(HANDLE hPrinter) 433 { 434 DWORD dwErrorCode; 435 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 436 437 TRACE("EndPagePrinter(%p)\n", hPrinter); 438 439 // Sanity checks. 440 if (!pHandle) 441 { 442 dwErrorCode = ERROR_INVALID_HANDLE; 443 goto Cleanup; 444 } 445 446 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE) 447 { 448 // For spooled jobs, we don't need to do anything. 449 dwErrorCode = ERROR_SUCCESS; 450 } 451 else 452 { 453 // In all other cases, just call _RpcEndPagePrinter. 454 RpcTryExcept 455 { 456 dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter); 457 } 458 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 459 { 460 dwErrorCode = RpcExceptionCode(); 461 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode); 462 } 463 RpcEndExcept; 464 } 465 466 Cleanup: 467 SetLastError(dwErrorCode); 468 return (dwErrorCode == ERROR_SUCCESS); 469 } 470 471 BOOL WINAPI 472 EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 473 { 474 BOOL bReturnValue = FALSE; 475 DWORD cch; 476 PWSTR pwszName = NULL; 477 PSTR pszPrinterName = NULL; 478 PSTR pszServerName = NULL; 479 PSTR pszDescription = NULL; 480 PSTR pszName = NULL; 481 PSTR pszComment = NULL; 482 PSTR pszShareName = NULL; 483 PSTR pszPortName = NULL; 484 PSTR pszDriverName = NULL; 485 PSTR pszLocation = NULL; 486 PSTR pszSepFile = NULL; 487 PSTR pszPrintProcessor = NULL; 488 PSTR pszDatatype = NULL; 489 PSTR pszParameters = NULL; 490 DWORD i; 491 PPRINTER_INFO_1W ppi1w = NULL; 492 PPRINTER_INFO_1A ppi1a = NULL; 493 PPRINTER_INFO_2W ppi2w = NULL; 494 PPRINTER_INFO_2A ppi2a = NULL; 495 PPRINTER_INFO_4W ppi4w = NULL; 496 PPRINTER_INFO_4A ppi4a = NULL; 497 PPRINTER_INFO_5W ppi5w = NULL; 498 PPRINTER_INFO_5A ppi5a = NULL; 499 500 TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); 501 502 // Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable. 503 if (Level != 1 && Level != 2 && Level != 4 && Level != 5) 504 { 505 SetLastError(ERROR_INVALID_LEVEL); 506 ERR("Invalid Level!\n"); 507 goto Cleanup; 508 } 509 510 if (Name) 511 { 512 // Convert pName to a Unicode string pwszName. 513 cch = strlen(Name); 514 515 pwszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 516 if (!pwszName) 517 { 518 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 519 ERR("HeapAlloc failed!\n"); 520 goto Cleanup; 521 } 522 523 MultiByteToWideChar(CP_ACP, 0, Name, -1, pwszName, cch + 1); 524 } 525 526 /* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */ 527 bReturnValue = EnumPrintersW(Flags, pwszName, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); 528 HeapFree(hProcessHeap, 0, pwszName); 529 530 TRACE("*pcReturned is '%d' and bReturnValue is '%d' and GetLastError is '%ld'.\n", *pcReturned, bReturnValue, GetLastError()); 531 532 /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */ 533 /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */ 534 /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */ 535 536 /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */ 537 ppi1w = (PPRINTER_INFO_1W)pPrinterEnum; 538 ppi2w = (PPRINTER_INFO_2W)pPrinterEnum; 539 ppi4w = (PPRINTER_INFO_4W)pPrinterEnum; 540 ppi5w = (PPRINTER_INFO_5W)pPrinterEnum; 541 /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */ 542 ppi1a = (PPRINTER_INFO_1A)pPrinterEnum; 543 ppi2a = (PPRINTER_INFO_2A)pPrinterEnum; 544 ppi4a = (PPRINTER_INFO_4A)pPrinterEnum; 545 ppi5a = (PPRINTER_INFO_5A)pPrinterEnum; 546 547 for (i = 0; i < *pcReturned; i++) 548 { 549 switch (Level) 550 { 551 case 1: 552 { 553 if (ppi1w[i].pDescription) 554 { 555 // Convert Unicode pDescription to a ANSI string pszDescription. 556 cch = wcslen(ppi1w[i].pDescription); 557 558 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 559 if (!pszDescription) 560 { 561 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 562 ERR("HeapAlloc failed!\n"); 563 goto Cleanup; 564 } 565 566 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pDescription, -1, pszDescription, cch + 1, NULL, NULL); 567 StringCchCopyA(ppi1a[i].pDescription, cch + 1, pszDescription); 568 569 HeapFree(hProcessHeap, 0, pszDescription); 570 } 571 572 if (ppi1w[i].pName) 573 { 574 // Convert Unicode pName to a ANSI string pszName. 575 cch = wcslen(ppi1w[i].pName); 576 577 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 578 if (!pszName) 579 { 580 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 581 ERR("HeapAlloc failed!\n"); 582 goto Cleanup; 583 } 584 585 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pName, -1, pszName, cch + 1, NULL, NULL); 586 StringCchCopyA(ppi1a[i].pName, cch + 1, pszName); 587 588 HeapFree(hProcessHeap, 0, pszName); 589 } 590 591 if (ppi1w[i].pComment) 592 { 593 // Convert Unicode pComment to a ANSI string pszComment. 594 cch = wcslen(ppi1w[i].pComment); 595 596 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 597 if (!pszComment) 598 { 599 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 600 ERR("HeapAlloc failed!\n"); 601 goto Cleanup; 602 } 603 604 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pComment, -1, pszComment, cch + 1, NULL, NULL); 605 StringCchCopyA(ppi1a[i].pComment, cch + 1, pszComment); 606 607 HeapFree(hProcessHeap, 0, pszComment); 608 } 609 break; 610 } 611 612 613 case 2: 614 { 615 if (ppi2w[i].pServerName) 616 { 617 // Convert Unicode pServerName to a ANSI string pszServerName. 618 cch = wcslen(ppi2w[i].pServerName); 619 620 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 621 if (!pszServerName) 622 { 623 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 624 ERR("HeapAlloc failed!\n"); 625 goto Cleanup; 626 } 627 628 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL); 629 StringCchCopyA(ppi2a[i].pServerName, cch + 1, pszServerName); 630 631 HeapFree(hProcessHeap, 0, pszServerName); 632 } 633 634 if (ppi2w[i].pPrinterName) 635 { 636 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 637 cch = wcslen(ppi2w[i].pPrinterName); 638 639 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 640 if (!pszPrinterName) 641 { 642 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 643 ERR("HeapAlloc failed!\n"); 644 goto Cleanup; 645 } 646 647 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 648 StringCchCopyA(ppi2a[i].pPrinterName, cch + 1, pszPrinterName); 649 650 HeapFree(hProcessHeap, 0, pszPrinterName); 651 } 652 653 if (ppi2w[i].pShareName) 654 { 655 // Convert Unicode pShareName to a ANSI string pszShareName. 656 cch = wcslen(ppi2w[i].pShareName); 657 658 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 659 if (!pszShareName) 660 { 661 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 662 ERR("HeapAlloc failed!\n"); 663 goto Cleanup; 664 } 665 666 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pShareName, -1, pszShareName, cch + 1, NULL, NULL); 667 StringCchCopyA(ppi2a[i].pShareName, cch + 1, pszShareName); 668 669 HeapFree(hProcessHeap, 0, pszShareName); 670 } 671 672 if (ppi2w[i].pPortName) 673 { 674 // Convert Unicode pPortName to a ANSI string pszPortName. 675 cch = wcslen(ppi2w[i].pPortName); 676 677 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 678 if (!pszPortName) 679 { 680 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 681 ERR("HeapAlloc failed!\n"); 682 goto Cleanup; 683 } 684 685 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL); 686 StringCchCopyA(ppi2a[i].pPortName, cch + 1, pszPortName); 687 688 HeapFree(hProcessHeap, 0, pszPortName); 689 } 690 691 if (ppi2w[i].pDriverName) 692 { 693 // Convert Unicode pDriverName to a ANSI string pszDriverName. 694 cch = wcslen(ppi2w[i].pDriverName); 695 696 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 697 if (!pszDriverName) 698 { 699 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 700 ERR("HeapAlloc failed!\n"); 701 goto Cleanup; 702 } 703 704 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDriverName, -1, pszDriverName, cch + 1, NULL, NULL); 705 StringCchCopyA(ppi2a[i].pDriverName, cch + 1, pszDriverName); 706 707 HeapFree(hProcessHeap, 0, pszDriverName); 708 } 709 710 if (ppi2w[i].pComment) 711 { 712 // Convert Unicode pComment to a ANSI string pszComment. 713 cch = wcslen(ppi2w[i].pComment); 714 715 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 716 if (!pszComment) 717 { 718 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 719 ERR("HeapAlloc failed!\n"); 720 goto Cleanup; 721 } 722 723 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pComment, -1, pszComment, cch + 1, NULL, NULL); 724 StringCchCopyA(ppi2a[i].pComment, cch + 1, pszComment); 725 726 HeapFree(hProcessHeap, 0, pszComment); 727 } 728 729 if (ppi2w[i].pLocation) 730 { 731 // Convert Unicode pLocation to a ANSI string pszLocation. 732 cch = wcslen(ppi2w[i].pLocation); 733 734 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 735 if (!pszLocation) 736 { 737 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 738 ERR("HeapAlloc failed!\n"); 739 goto Cleanup; 740 } 741 742 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pLocation, -1, pszLocation, cch + 1, NULL, NULL); 743 StringCchCopyA(ppi2a[i].pLocation, cch + 1, pszLocation); 744 745 HeapFree(hProcessHeap, 0, pszLocation); 746 } 747 748 749 if (ppi2w[i].pSepFile) 750 { 751 // Convert Unicode pSepFile to a ANSI string pszSepFile. 752 cch = wcslen(ppi2w[i].pSepFile); 753 754 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 755 if (!pszSepFile) 756 { 757 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 758 ERR("HeapAlloc failed!\n"); 759 goto Cleanup; 760 } 761 762 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pSepFile, -1, pszSepFile, cch + 1, NULL, NULL); 763 StringCchCopyA(ppi2a[i].pSepFile, cch + 1, pszSepFile); 764 765 HeapFree(hProcessHeap, 0, pszSepFile); 766 } 767 768 if (ppi2w[i].pPrintProcessor) 769 { 770 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor. 771 cch = wcslen(ppi2w[i].pPrintProcessor); 772 773 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 774 if (!pszPrintProcessor) 775 { 776 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 777 ERR("HeapAlloc failed!\n"); 778 goto Cleanup; 779 } 780 781 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL); 782 StringCchCopyA(ppi2a[i].pPrintProcessor, cch + 1, pszPrintProcessor); 783 784 HeapFree(hProcessHeap, 0, pszPrintProcessor); 785 } 786 787 788 if (ppi2w[i].pDatatype) 789 { 790 // Convert Unicode pDatatype to a ANSI string pszDatatype. 791 cch = wcslen(ppi2w[i].pDatatype); 792 793 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 794 if (!pszDatatype) 795 { 796 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 797 ERR("HeapAlloc failed!\n"); 798 goto Cleanup; 799 } 800 801 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDatatype, -1, pszDatatype, cch + 1, NULL, NULL); 802 StringCchCopyA(ppi2a[i].pDatatype, cch + 1, pszDatatype); 803 804 HeapFree(hProcessHeap, 0, pszDatatype); 805 } 806 807 if (ppi2w[i].pParameters) 808 { 809 // Convert Unicode pParameters to a ANSI string pszParameters. 810 cch = wcslen(ppi2w[i].pParameters); 811 812 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 813 if (!pszParameters) 814 { 815 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 816 ERR("HeapAlloc failed!\n"); 817 goto Cleanup; 818 } 819 820 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pParameters, -1, pszParameters, cch + 1, NULL, NULL); 821 StringCchCopyA(ppi2a[i].pParameters, cch + 1, pszParameters); 822 823 HeapFree(hProcessHeap, 0, pszParameters); 824 } 825 break; 826 827 } 828 829 case 4: 830 { 831 if (ppi4w[i].pPrinterName) 832 { 833 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 834 cch = wcslen(ppi4w[i].pPrinterName); 835 836 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 837 if (!pszPrinterName) 838 { 839 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 840 ERR("HeapAlloc failed!\n"); 841 goto Cleanup; 842 } 843 844 WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 845 StringCchCopyA(ppi4a[i].pPrinterName, cch + 1, pszPrinterName); 846 847 HeapFree(hProcessHeap, 0, pszPrinterName); 848 } 849 850 if (ppi4w[i].pServerName) 851 { 852 // Convert Unicode pServerName to a ANSI string pszServerName. 853 cch = wcslen(ppi4w[i].pServerName); 854 855 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 856 if (!pszServerName) 857 { 858 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 859 ERR("HeapAlloc failed!\n"); 860 goto Cleanup; 861 } 862 863 WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL); 864 StringCchCopyA(ppi4a[i].pServerName, cch + 1, pszServerName); 865 866 HeapFree(hProcessHeap, 0, pszServerName); 867 } 868 break; 869 } 870 871 case 5: 872 { 873 if (ppi5w[i].pPrinterName) 874 { 875 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 876 cch = wcslen(ppi5w[i].pPrinterName); 877 878 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 879 if (!pszPrinterName) 880 { 881 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 882 ERR("HeapAlloc failed!\n"); 883 goto Cleanup; 884 } 885 886 WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 887 StringCchCopyA(ppi5a[i].pPrinterName, cch + 1, pszPrinterName); 888 889 HeapFree(hProcessHeap, 0, pszPrinterName); 890 } 891 892 if (ppi5w[i].pPortName) 893 { 894 // Convert Unicode pPortName to a ANSI string pszPortName. 895 cch = wcslen(ppi5w[i].pPortName); 896 897 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 898 if (!pszPortName) 899 { 900 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 901 ERR("HeapAlloc failed!\n"); 902 goto Cleanup; 903 } 904 905 WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL); 906 StringCchCopyA(ppi5a[i].pPortName, cch + 1, pszPortName); 907 908 HeapFree(hProcessHeap, 0, pszPortName); 909 } 910 break; 911 } 912 913 } // switch 914 } // for 915 916 Cleanup: 917 918 return bReturnValue; 919 } 920 921 BOOL WINAPI 922 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 923 { 924 DWORD dwErrorCode; 925 926 TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); 927 928 // Dismiss invalid levels already at this point. 929 if (Level == 3 || Level > 5) 930 { 931 dwErrorCode = ERROR_INVALID_LEVEL; 932 goto Cleanup; 933 } 934 935 if (cbBuf && pPrinterEnum) 936 ZeroMemory(pPrinterEnum, cbBuf); 937 938 // Do the RPC call 939 RpcTryExcept 940 { 941 dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); 942 } 943 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 944 { 945 dwErrorCode = RpcExceptionCode(); 946 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode); 947 } 948 RpcEndExcept; 949 950 if (dwErrorCode == ERROR_SUCCESS) 951 { 952 // Replace relative offset addresses in the output by absolute pointers. 953 ASSERT(Level <= 9); 954 MarshallUpStructuresArray(cbBuf, pPrinterEnum, *pcReturned, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE); 955 } 956 957 Cleanup: 958 SetLastError(dwErrorCode); 959 return (dwErrorCode == ERROR_SUCCESS); 960 } 961 962 BOOL WINAPI 963 FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep) 964 { 965 TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter, pBuf, cbBuf, pcWritten, cSleep); 966 UNIMPLEMENTED; 967 return FALSE; 968 } 969 970 BOOL WINAPI 971 GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer) 972 { 973 DWORD dwErrorCode; 974 PWSTR pwszBuffer = NULL; 975 976 TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer, pcchBuffer); 977 978 // Sanity check. 979 if (!pcchBuffer) 980 { 981 dwErrorCode = ERROR_INVALID_PARAMETER; 982 goto Cleanup; 983 } 984 985 // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size. 986 if (pszBuffer && *pcchBuffer) 987 { 988 pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR)); 989 if (!pwszBuffer) 990 { 991 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 992 ERR("HeapAlloc failed!\n"); 993 goto Cleanup; 994 } 995 } 996 997 if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer)) 998 { 999 dwErrorCode = GetLastError(); 1000 goto Cleanup; 1001 } 1002 1003 // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI. 1004 WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, *pcchBuffer, NULL, NULL); 1005 1006 dwErrorCode = ERROR_SUCCESS; 1007 1008 Cleanup: 1009 if (pwszBuffer) 1010 HeapFree(hProcessHeap, 0, pwszBuffer); 1011 1012 SetLastError(dwErrorCode); 1013 return (dwErrorCode == ERROR_SUCCESS); 1014 } 1015 1016 BOOL WINAPI 1017 GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer) 1018 { 1019 DWORD cbNeeded; 1020 DWORD cchInputBuffer; 1021 DWORD dwErrorCode; 1022 HKEY hWindowsKey = NULL; 1023 PWSTR pwszDevice = NULL; 1024 PWSTR pwszComma; 1025 1026 TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer, pcchBuffer); 1027 1028 // Sanity check. 1029 if (!pcchBuffer) 1030 { 1031 dwErrorCode = ERROR_INVALID_PARAMETER; 1032 goto Cleanup; 1033 } 1034 1035 cchInputBuffer = *pcchBuffer; 1036 1037 // Open the registry key where the default printer for the current user is stored. 1038 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey); 1039 if (dwErrorCode != ERROR_SUCCESS) 1040 { 1041 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); 1042 goto Cleanup; 1043 } 1044 1045 // Determine the size of the required buffer. 1046 dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded); 1047 if (dwErrorCode != ERROR_SUCCESS) 1048 { 1049 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); 1050 goto Cleanup; 1051 } 1052 1053 // Allocate it. 1054 pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded); 1055 if (!pwszDevice) 1056 { 1057 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1058 ERR("HeapAlloc failed!\n"); 1059 goto Cleanup; 1060 } 1061 1062 // Now get the actual value. 1063 dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded); 1064 if (dwErrorCode != ERROR_SUCCESS) 1065 { 1066 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); 1067 goto Cleanup; 1068 } 1069 1070 // We get a string "<Printer Name>,winspool,<Port>:". 1071 // Extract the printer name from it. 1072 pwszComma = wcschr(pwszDevice, L','); 1073 if (!pwszComma) 1074 { 1075 ERR("Found no or invalid default printer: %S!\n", pwszDevice); 1076 dwErrorCode = ERROR_INVALID_NAME; 1077 goto Cleanup; 1078 } 1079 1080 // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer. 1081 *pcchBuffer = pwszComma - pwszDevice + 1; 1082 1083 // Check if the supplied buffer is large enough. 1084 if (cchInputBuffer < *pcchBuffer) 1085 { 1086 dwErrorCode = ERROR_INSUFFICIENT_BUFFER; 1087 goto Cleanup; 1088 } 1089 1090 // Copy the default printer. 1091 *pwszComma = 0; 1092 CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR)); 1093 1094 dwErrorCode = ERROR_SUCCESS; 1095 1096 Cleanup: 1097 if (hWindowsKey) 1098 RegCloseKey(hWindowsKey); 1099 1100 if (pwszDevice) 1101 HeapFree(hProcessHeap, 0, pwszDevice); 1102 1103 SetLastError(dwErrorCode); 1104 return (dwErrorCode == ERROR_SUCCESS); 1105 } 1106 1107 BOOL WINAPI 1108 GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) 1109 { 1110 PPRINTER_INFO_1A ppi1a = (PPRINTER_INFO_1A)pPrinter; 1111 PPRINTER_INFO_1W ppi1w = (PPRINTER_INFO_1W)pPrinter; 1112 PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter; 1113 PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter; 1114 PPRINTER_INFO_4A ppi4a = (PPRINTER_INFO_4A)pPrinter; 1115 PPRINTER_INFO_4W ppi4w = (PPRINTER_INFO_4W)pPrinter; 1116 PPRINTER_INFO_5A ppi5a = (PPRINTER_INFO_5A)pPrinter; 1117 PPRINTER_INFO_5W ppi5w = (PPRINTER_INFO_5W)pPrinter; 1118 PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter; 1119 PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter; 1120 DWORD cch; 1121 BOOL bReturnValue = FALSE; 1122 1123 TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 1124 1125 // Check for invalid levels here for early error return. Should be 1-9. 1126 if (Level < 1 || Level > 9) 1127 { 1128 SetLastError(ERROR_INVALID_LEVEL); 1129 ERR("Invalid Level!\n"); 1130 goto Cleanup; 1131 } 1132 1133 bReturnValue = GetPrinterW(hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 1134 1135 if (!bReturnValue) 1136 { 1137 TRACE("GetPrinterW failed!\n"); 1138 goto Cleanup; 1139 } 1140 1141 switch (Level) 1142 { 1143 case 1: 1144 { 1145 if (ppi1w->pDescription) 1146 { 1147 PSTR pszDescription; 1148 1149 // Convert Unicode pDescription to a ANSI string pszDescription. 1150 cch = wcslen(ppi1w->pDescription); 1151 1152 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1153 if (!pszDescription) 1154 { 1155 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1156 ERR("HeapAlloc failed!\n"); 1157 goto Cleanup; 1158 } 1159 1160 WideCharToMultiByte(CP_ACP, 0, ppi1w->pDescription, -1, pszDescription, cch + 1, NULL, NULL); 1161 StringCchCopyA(ppi1a->pDescription, cch + 1, pszDescription); 1162 1163 HeapFree(hProcessHeap, 0, pszDescription); 1164 } 1165 1166 if (ppi1w->pName) 1167 { 1168 PSTR pszName; 1169 1170 // Convert Unicode pName to a ANSI string pszName. 1171 cch = wcslen(ppi1w->pName); 1172 1173 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1174 if (!pszName) 1175 { 1176 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1177 ERR("HeapAlloc failed!\n"); 1178 goto Cleanup; 1179 } 1180 1181 WideCharToMultiByte(CP_ACP, 0, ppi1w->pName, -1, pszName, cch + 1, NULL, NULL); 1182 StringCchCopyA(ppi1a->pName, cch + 1, pszName); 1183 1184 HeapFree(hProcessHeap, 0, pszName); 1185 } 1186 1187 if (ppi1w->pComment) 1188 { 1189 PSTR pszComment; 1190 1191 // Convert Unicode pComment to a ANSI string pszComment. 1192 cch = wcslen(ppi1w->pComment); 1193 1194 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1195 if (!pszComment) 1196 { 1197 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1198 ERR("HeapAlloc failed!\n"); 1199 goto Cleanup; 1200 } 1201 1202 WideCharToMultiByte(CP_ACP, 0, ppi1w->pComment, -1, pszComment, cch + 1, NULL, NULL); 1203 StringCchCopyA(ppi1a->pComment, cch + 1, pszComment); 1204 1205 HeapFree(hProcessHeap, 0, pszComment); 1206 } 1207 break; 1208 } 1209 1210 case 2: 1211 { 1212 if (ppi2w->pServerName) 1213 { 1214 PSTR pszServerName; 1215 1216 // Convert Unicode pServerName to a ANSI string pszServerName. 1217 cch = wcslen(ppi2w->pServerName); 1218 1219 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1220 if (!pszServerName) 1221 { 1222 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1223 ERR("HeapAlloc failed!\n"); 1224 goto Cleanup; 1225 } 1226 1227 WideCharToMultiByte(CP_ACP, 0, ppi2w->pServerName, -1, pszServerName, cch + 1, NULL, NULL); 1228 StringCchCopyA(ppi2a->pServerName, cch + 1, pszServerName); 1229 1230 HeapFree(hProcessHeap, 0, pszServerName); 1231 } 1232 1233 if (ppi2w->pPrinterName) 1234 { 1235 PSTR pszPrinterName; 1236 1237 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 1238 cch = wcslen(ppi2w->pPrinterName); 1239 1240 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1241 if (!pszPrinterName) 1242 { 1243 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1244 ERR("HeapAlloc failed!\n"); 1245 goto Cleanup; 1246 } 1247 1248 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 1249 StringCchCopyA(ppi2a->pPrinterName, cch + 1, pszPrinterName); 1250 1251 HeapFree(hProcessHeap, 0, pszPrinterName); 1252 } 1253 1254 if (ppi2w->pShareName) 1255 { 1256 PSTR pszShareName; 1257 1258 // Convert Unicode pShareName to a ANSI string pszShareName. 1259 cch = wcslen(ppi2w->pShareName); 1260 1261 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1262 if (!pszShareName) 1263 { 1264 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1265 ERR("HeapAlloc failed!\n"); 1266 goto Cleanup; 1267 } 1268 1269 WideCharToMultiByte(CP_ACP, 0, ppi2w->pShareName, -1, pszShareName, cch + 1, NULL, NULL); 1270 StringCchCopyA(ppi2a->pShareName, cch + 1, pszShareName); 1271 1272 HeapFree(hProcessHeap, 0, pszShareName); 1273 } 1274 1275 if (ppi2w->pPortName) 1276 { 1277 PSTR pszPortName; 1278 1279 // Convert Unicode pPortName to a ANSI string pszPortName. 1280 cch = wcslen(ppi2w->pPortName); 1281 1282 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1283 if (!pszPortName) 1284 { 1285 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1286 ERR("HeapAlloc failed!\n"); 1287 goto Cleanup; 1288 } 1289 1290 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPortName, -1, pszPortName, cch + 1, NULL, NULL); 1291 StringCchCopyA(ppi2a->pPortName, cch + 1, pszPortName); 1292 1293 HeapFree(hProcessHeap, 0, pszPortName); 1294 } 1295 1296 if (ppi2w->pDriverName) 1297 { 1298 PSTR pszDriverName; 1299 1300 // Convert Unicode pDriverName to a ANSI string pszDriverName. 1301 cch = wcslen(ppi2w->pDriverName); 1302 1303 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1304 if (!pszDriverName) 1305 { 1306 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1307 ERR("HeapAlloc failed!\n"); 1308 goto Cleanup; 1309 } 1310 1311 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDriverName, -1, pszDriverName, cch + 1, NULL, NULL); 1312 StringCchCopyA(ppi2a->pDriverName, cch + 1, pszDriverName); 1313 1314 HeapFree(hProcessHeap, 0, pszDriverName); 1315 } 1316 1317 if (ppi2w->pComment) 1318 { 1319 PSTR pszComment; 1320 1321 // Convert Unicode pComment to a ANSI string pszComment. 1322 cch = wcslen(ppi2w->pComment); 1323 1324 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1325 if (!pszComment) 1326 { 1327 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1328 ERR("HeapAlloc failed!\n"); 1329 goto Cleanup; 1330 } 1331 1332 WideCharToMultiByte(CP_ACP, 0, ppi2w->pComment, -1, pszComment, cch + 1, NULL, NULL); 1333 StringCchCopyA(ppi2a->pComment, cch + 1, pszComment); 1334 1335 HeapFree(hProcessHeap, 0, pszComment); 1336 } 1337 1338 if (ppi2w->pLocation) 1339 { 1340 PSTR pszLocation; 1341 1342 // Convert Unicode pLocation to a ANSI string pszLocation. 1343 cch = wcslen(ppi2w->pLocation); 1344 1345 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1346 if (!pszLocation) 1347 { 1348 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1349 ERR("HeapAlloc failed!\n"); 1350 goto Cleanup; 1351 } 1352 1353 WideCharToMultiByte(CP_ACP, 0, ppi2w->pLocation, -1, pszLocation, cch + 1, NULL, NULL); 1354 StringCchCopyA(ppi2a->pLocation, cch + 1, pszLocation); 1355 1356 HeapFree(hProcessHeap, 0, pszLocation); 1357 } 1358 1359 if (ppi2w->pSepFile) 1360 { 1361 PSTR pszSepFile; 1362 1363 // Convert Unicode pSepFile to a ANSI string pszSepFile. 1364 cch = wcslen(ppi2w->pSepFile); 1365 1366 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1367 if (!pszSepFile) 1368 { 1369 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1370 ERR("HeapAlloc failed!\n"); 1371 goto Cleanup; 1372 } 1373 1374 WideCharToMultiByte(CP_ACP, 0, ppi2w->pSepFile, -1, pszSepFile, cch + 1, NULL, NULL); 1375 StringCchCopyA(ppi2a->pSepFile, cch + 1, pszSepFile); 1376 1377 HeapFree(hProcessHeap, 0, pszSepFile); 1378 } 1379 1380 if (ppi2w->pPrintProcessor) 1381 { 1382 PSTR pszPrintProcessor; 1383 1384 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor. 1385 cch = wcslen(ppi2w->pPrintProcessor); 1386 1387 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1388 if (!pszPrintProcessor) 1389 { 1390 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1391 ERR("HeapAlloc failed!\n"); 1392 goto Cleanup; 1393 } 1394 1395 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL); 1396 StringCchCopyA(ppi2a->pPrintProcessor, cch + 1, pszPrintProcessor); 1397 1398 HeapFree(hProcessHeap, 0, pszPrintProcessor); 1399 } 1400 1401 if (ppi2w->pDatatype) 1402 { 1403 PSTR pszDatatype; 1404 1405 // Convert Unicode pDatatype to a ANSI string pszDatatype. 1406 cch = wcslen(ppi2w->pDatatype); 1407 1408 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1409 if (!pszDatatype) 1410 { 1411 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1412 ERR("HeapAlloc failed!\n"); 1413 goto Cleanup; 1414 } 1415 1416 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDatatype, -1, pszDatatype, cch + 1, NULL, NULL); 1417 StringCchCopyA(ppi2a->pDatatype, cch + 1, pszDatatype); 1418 1419 HeapFree(hProcessHeap, 0, pszDatatype); 1420 } 1421 1422 if (ppi2w->pParameters) 1423 { 1424 PSTR pszParameters; 1425 1426 // Convert Unicode pParameters to a ANSI string pszParameters. 1427 cch = wcslen(ppi2w->pParameters); 1428 1429 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1430 if (!pszParameters) 1431 { 1432 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1433 ERR("HeapAlloc failed!\n"); 1434 goto Cleanup; 1435 } 1436 1437 WideCharToMultiByte(CP_ACP, 0, ppi2w->pParameters, -1, pszParameters, cch + 1, NULL, NULL); 1438 StringCchCopyA(ppi2a->pParameters, cch + 1, pszParameters); 1439 1440 HeapFree(hProcessHeap, 0, pszParameters); 1441 } 1442 break; 1443 } 1444 1445 case 4: 1446 { 1447 if (ppi4w->pPrinterName) 1448 { 1449 PSTR pszPrinterName; 1450 1451 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 1452 cch = wcslen(ppi4w->pPrinterName); 1453 1454 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1455 if (!pszPrinterName) 1456 { 1457 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1458 ERR("HeapAlloc failed!\n"); 1459 goto Cleanup; 1460 } 1461 1462 WideCharToMultiByte(CP_ACP, 0, ppi4w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 1463 StringCchCopyA(ppi4a->pPrinterName, cch + 1, pszPrinterName); 1464 1465 HeapFree(hProcessHeap, 0, pszPrinterName); 1466 } 1467 1468 if (ppi4w->pServerName) 1469 { 1470 PSTR pszServerName; 1471 1472 // Convert Unicode pServerName to a ANSI string pszServerName. 1473 cch = wcslen(ppi4w->pServerName); 1474 1475 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1476 if (!pszServerName) 1477 { 1478 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1479 ERR("HeapAlloc failed!\n"); 1480 goto Cleanup; 1481 } 1482 1483 WideCharToMultiByte(CP_ACP, 0, ppi4w->pServerName, -1, pszServerName, cch + 1, NULL, NULL); 1484 StringCchCopyA(ppi4a->pServerName, cch + 1, pszServerName); 1485 1486 HeapFree(hProcessHeap, 0, pszServerName); 1487 } 1488 break; 1489 } 1490 1491 case 5: 1492 { 1493 if (ppi5w->pPrinterName) 1494 { 1495 PSTR pszPrinterName; 1496 1497 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 1498 cch = wcslen(ppi5w->pPrinterName); 1499 1500 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1501 if (!pszPrinterName) 1502 { 1503 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1504 ERR("HeapAlloc failed!\n"); 1505 goto Cleanup; 1506 } 1507 1508 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 1509 StringCchCopyA(ppi5a->pPrinterName, cch + 1, pszPrinterName); 1510 1511 HeapFree(hProcessHeap, 0, pszPrinterName); 1512 } 1513 1514 if (ppi5w->pPortName) 1515 { 1516 PSTR pszPortName; 1517 1518 // Convert Unicode pPortName to a ANSI string pszPortName. 1519 cch = wcslen(ppi5w->pPortName); 1520 1521 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1522 if (!pszPortName) 1523 { 1524 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1525 ERR("HeapAlloc failed!\n"); 1526 goto Cleanup; 1527 } 1528 1529 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPortName, -1, pszPortName, cch + 1, NULL, NULL); 1530 StringCchCopyA(ppi5a->pPortName, cch + 1, pszPortName); 1531 1532 HeapFree(hProcessHeap, 0, pszPortName); 1533 } 1534 break; 1535 } 1536 1537 case 7: 1538 { 1539 if (ppi7w->pszObjectGUID) 1540 { 1541 PSTR pszaObjectGUID; 1542 1543 // Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID. 1544 cch = wcslen(ppi7w->pszObjectGUID); 1545 1546 pszaObjectGUID = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1547 if (!pszaObjectGUID) 1548 { 1549 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1550 ERR("HeapAlloc failed!\n"); 1551 goto Cleanup; 1552 } 1553 1554 WideCharToMultiByte(CP_ACP, 0, ppi7w->pszObjectGUID, -1, pszaObjectGUID, cch + 1, NULL, NULL); 1555 StringCchCopyA(ppi7a->pszObjectGUID, cch + 1, pszaObjectGUID); 1556 1557 HeapFree(hProcessHeap, 0, pszaObjectGUID); 1558 } 1559 break; 1560 } 1561 } // switch 1562 1563 Cleanup: 1564 return bReturnValue; 1565 } 1566 1567 BOOL WINAPI 1568 GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) 1569 { 1570 /* 1571 * We are mapping multiple different pointers to the same pDriverInfo pointer here so that 1572 * we can use the same incoming pointer for different Levels 1573 */ 1574 PDRIVER_INFO_1W pdi1w = (PDRIVER_INFO_1W)pDriverInfo; 1575 PDRIVER_INFO_2W pdi2w = (PDRIVER_INFO_2W)pDriverInfo; 1576 PDRIVER_INFO_3W pdi3w = (PDRIVER_INFO_3W)pDriverInfo; 1577 PDRIVER_INFO_4W pdi4w = (PDRIVER_INFO_4W)pDriverInfo; 1578 PDRIVER_INFO_5W pdi5w = (PDRIVER_INFO_5W)pDriverInfo; 1579 PDRIVER_INFO_6W pdi6w = (PDRIVER_INFO_6W)pDriverInfo; 1580 1581 BOOL bReturnValue = FALSE; 1582 DWORD cch; 1583 PWSTR pwszEnvironment = NULL; 1584 1585 TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); 1586 1587 // Check for invalid levels here for early error return. Should be 1-6. 1588 if (Level < 1 || Level > 6) 1589 { 1590 SetLastError(ERROR_INVALID_LEVEL); 1591 ERR("Invalid Level!\n"); 1592 goto Exit; 1593 } 1594 1595 if (pEnvironment) 1596 { 1597 // Convert pEnvironment to a Unicode string pwszEnvironment. 1598 cch = strlen(pEnvironment); 1599 1600 pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 1601 if (!pwszEnvironment) 1602 { 1603 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1604 ERR("HeapAlloc failed!\n"); 1605 goto Exit; 1606 } 1607 1608 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, pwszEnvironment, cch + 1); 1609 } 1610 1611 bReturnValue = GetPrinterDriverW(hPrinter, pwszEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); 1612 TRACE("*pcbNeeded is '%d' and bReturnValue is '%d' and GetLastError is '%ld'.\n", *pcbNeeded, bReturnValue, GetLastError()); 1613 1614 if (pwszEnvironment) 1615 { 1616 HeapFree(hProcessHeap, 0, pwszEnvironment); 1617 } 1618 1619 if (!bReturnValue) 1620 { 1621 TRACE("GetPrinterDriverW failed!\n"); 1622 goto Exit; 1623 } 1624 1625 // Do Unicode to ANSI conversions for strings based on Level 1626 switch (Level) 1627 { 1628 case 1: 1629 { 1630 if (!UnicodeToAnsiInPlace(pdi1w->pName)) 1631 goto Exit; 1632 1633 break; 1634 } 1635 1636 case 2: 1637 { 1638 if (!UnicodeToAnsiInPlace(pdi2w->pName)) 1639 goto Exit; 1640 1641 if (!UnicodeToAnsiInPlace(pdi2w->pEnvironment)) 1642 goto Exit; 1643 1644 if (!UnicodeToAnsiInPlace(pdi2w->pDriverPath)) 1645 goto Exit; 1646 1647 if (!UnicodeToAnsiInPlace(pdi2w->pDataFile)) 1648 goto Exit; 1649 1650 if (!UnicodeToAnsiInPlace(pdi2w->pConfigFile)) 1651 goto Exit; 1652 1653 break; 1654 } 1655 1656 case 3: 1657 { 1658 if (!UnicodeToAnsiInPlace(pdi3w->pName)) 1659 goto Exit; 1660 1661 if (!UnicodeToAnsiInPlace(pdi3w->pEnvironment)) 1662 goto Exit; 1663 1664 if (!UnicodeToAnsiInPlace(pdi3w->pDriverPath)) 1665 goto Exit; 1666 1667 if (!UnicodeToAnsiInPlace(pdi3w->pDataFile)) 1668 goto Exit; 1669 1670 if (!UnicodeToAnsiInPlace(pdi3w->pConfigFile)) 1671 goto Exit; 1672 1673 if (!UnicodeToAnsiInPlace(pdi3w->pHelpFile)) 1674 goto Exit; 1675 1676 if (!UnicodeToAnsiInPlace(pdi3w->pDependentFiles)) 1677 goto Exit; 1678 1679 if (!UnicodeToAnsiInPlace(pdi3w->pMonitorName)) 1680 goto Exit; 1681 1682 if (!UnicodeToAnsiInPlace(pdi3w->pDefaultDataType)) 1683 goto Exit; 1684 1685 break; 1686 } 1687 1688 case 4: 1689 { 1690 if (!UnicodeToAnsiInPlace(pdi4w->pName)) 1691 goto Exit; 1692 1693 if (!UnicodeToAnsiInPlace(pdi4w->pEnvironment)) 1694 goto Exit; 1695 1696 if (!UnicodeToAnsiInPlace(pdi4w->pDriverPath)) 1697 goto Exit; 1698 1699 if (!UnicodeToAnsiInPlace(pdi4w->pDataFile)) 1700 goto Exit; 1701 1702 if (!UnicodeToAnsiInPlace(pdi4w->pConfigFile)) 1703 goto Exit; 1704 1705 if (!UnicodeToAnsiInPlace(pdi4w->pHelpFile)) 1706 goto Exit; 1707 1708 if (!UnicodeToAnsiInPlace(pdi4w->pDependentFiles)) 1709 goto Exit; 1710 1711 if (!UnicodeToAnsiInPlace(pdi4w->pMonitorName)) 1712 goto Exit; 1713 1714 if (!UnicodeToAnsiInPlace(pdi4w->pDefaultDataType)) 1715 goto Exit; 1716 1717 if (!UnicodeToAnsiInPlace(pdi4w->pszzPreviousNames)) 1718 goto Exit; 1719 1720 break; 1721 } 1722 1723 case 5: 1724 { 1725 if (!UnicodeToAnsiInPlace(pdi5w->pName)) 1726 goto Exit; 1727 1728 if (!UnicodeToAnsiInPlace(pdi5w->pEnvironment)) 1729 goto Exit; 1730 1731 if (!UnicodeToAnsiInPlace(pdi5w->pDriverPath)) 1732 goto Exit; 1733 1734 if (!UnicodeToAnsiInPlace(pdi5w->pDataFile)) 1735 goto Exit; 1736 1737 if (!UnicodeToAnsiInPlace(pdi5w->pConfigFile)) 1738 goto Exit; 1739 1740 break; 1741 } 1742 1743 case 6: 1744 { 1745 if (!UnicodeToAnsiInPlace(pdi6w->pName)) 1746 goto Exit; 1747 1748 if (!UnicodeToAnsiInPlace(pdi6w->pEnvironment)) 1749 goto Exit; 1750 1751 if (!UnicodeToAnsiInPlace(pdi6w->pDriverPath)) 1752 goto Exit; 1753 1754 if (!UnicodeToAnsiInPlace(pdi6w->pDataFile)) 1755 goto Exit; 1756 1757 if (!UnicodeToAnsiInPlace(pdi6w->pConfigFile)) 1758 goto Exit; 1759 1760 if (!UnicodeToAnsiInPlace(pdi6w->pHelpFile)) 1761 goto Exit; 1762 1763 if (!UnicodeToAnsiInPlace(pdi6w->pDependentFiles)) 1764 goto Exit; 1765 1766 if (!UnicodeToAnsiInPlace(pdi6w->pMonitorName)) 1767 goto Exit; 1768 1769 if (!UnicodeToAnsiInPlace(pdi6w->pDefaultDataType)) 1770 goto Exit; 1771 1772 if (!UnicodeToAnsiInPlace(pdi6w->pszzPreviousNames)) 1773 goto Exit; 1774 1775 if (!UnicodeToAnsiInPlace(pdi6w->pszMfgName)) 1776 goto Exit; 1777 1778 if (!UnicodeToAnsiInPlace(pdi6w->pszOEMUrl)) 1779 goto Exit; 1780 1781 if (!UnicodeToAnsiInPlace(pdi6w->pszHardwareID)) 1782 goto Exit; 1783 1784 if (!UnicodeToAnsiInPlace(pdi6w->pszProvider)) 1785 goto Exit; 1786 } 1787 } 1788 1789 bReturnValue = TRUE; 1790 1791 Exit: 1792 1793 return bReturnValue; 1794 } 1795 1796 BOOL WINAPI 1797 GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) 1798 { 1799 DWORD dwErrorCode; 1800 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 1801 1802 TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); 1803 1804 // Sanity checks. 1805 if (!pHandle) 1806 { 1807 dwErrorCode = ERROR_INVALID_HANDLE; 1808 goto Cleanup; 1809 } 1810 1811 // Dismiss invalid levels already at this point. 1812 if (Level > 8 || Level < 1) 1813 { 1814 dwErrorCode = ERROR_INVALID_LEVEL; 1815 goto Cleanup; 1816 } 1817 1818 if (cbBuf && pDriverInfo) 1819 ZeroMemory(pDriverInfo, cbBuf); 1820 1821 // Do the RPC call 1822 RpcTryExcept 1823 { 1824 dwErrorCode = _RpcGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); 1825 } 1826 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 1827 { 1828 dwErrorCode = RpcExceptionCode(); 1829 ERR("_RpcGetPrinterDriver failed with exception code %lu!\n", dwErrorCode); 1830 } 1831 RpcEndExcept; 1832 1833 if (dwErrorCode == ERROR_SUCCESS) 1834 { 1835 // Replace relative offset addresses in the output by absolute pointers. 1836 ASSERT(Level <= 5); 1837 MarshallUpStructure(cbBuf, pDriverInfo, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE); 1838 } 1839 1840 Cleanup: 1841 SetLastError(dwErrorCode); 1842 return (dwErrorCode == ERROR_SUCCESS); 1843 } 1844 1845 BOOL WINAPI 1846 GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) 1847 { 1848 DWORD dwErrorCode; 1849 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 1850 1851 TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 1852 1853 // Sanity checks. 1854 if (!pHandle) 1855 { 1856 dwErrorCode = ERROR_INVALID_HANDLE; 1857 goto Cleanup; 1858 } 1859 1860 // Dismiss invalid levels already at this point. 1861 if (Level > 9) 1862 { 1863 dwErrorCode = ERROR_INVALID_LEVEL; 1864 goto Cleanup; 1865 } 1866 1867 if (cbBuf && pPrinter) 1868 ZeroMemory(pPrinter, cbBuf); 1869 1870 // Do the RPC call 1871 RpcTryExcept 1872 { 1873 dwErrorCode = _RpcGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 1874 } 1875 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 1876 { 1877 dwErrorCode = RpcExceptionCode(); 1878 ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode); 1879 } 1880 RpcEndExcept; 1881 1882 if (dwErrorCode == ERROR_SUCCESS) 1883 { 1884 // Replace relative offset addresses in the output by absolute pointers. 1885 ASSERT(Level <= 9); 1886 MarshallUpStructure(cbBuf, pPrinter, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE); 1887 } 1888 1889 Cleanup: 1890 SetLastError(dwErrorCode); 1891 return (dwErrorCode == ERROR_SUCCESS); 1892 } 1893 1894 BOOL WINAPI 1895 OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault) 1896 { 1897 BOOL bReturnValue = FALSE; 1898 DWORD cch; 1899 PWSTR pwszPrinterName = NULL; 1900 PRINTER_DEFAULTSW wDefault = { 0 }; 1901 1902 TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName, phPrinter, pDefault); 1903 1904 if (pPrinterName) 1905 { 1906 // Convert pPrinterName to a Unicode string pwszPrinterName 1907 cch = strlen(pPrinterName); 1908 1909 pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 1910 if (!pwszPrinterName) 1911 { 1912 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1913 ERR("HeapAlloc failed!\n"); 1914 goto Cleanup; 1915 } 1916 1917 MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, cch + 1); 1918 } 1919 1920 if (pDefault) 1921 { 1922 wDefault.DesiredAccess = pDefault->DesiredAccess; 1923 1924 if (pDefault->pDatatype) 1925 { 1926 // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype 1927 cch = strlen(pDefault->pDatatype); 1928 1929 wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 1930 if (!wDefault.pDatatype) 1931 { 1932 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1933 ERR("HeapAlloc failed!\n"); 1934 goto Cleanup; 1935 } 1936 1937 MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, wDefault.pDatatype, cch + 1); 1938 } 1939 1940 if (pDefault->pDevMode) 1941 wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode); 1942 } 1943 1944 bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault); 1945 1946 Cleanup: 1947 if (wDefault.pDatatype) 1948 HeapFree(hProcessHeap, 0, wDefault.pDatatype); 1949 1950 if (wDefault.pDevMode) 1951 HeapFree(hProcessHeap, 0, wDefault.pDevMode); 1952 1953 if (pwszPrinterName) 1954 HeapFree(hProcessHeap, 0, pwszPrinterName); 1955 1956 return bReturnValue; 1957 } 1958 1959 BOOL WINAPI 1960 OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault) 1961 { 1962 DWORD dwErrorCode; 1963 HANDLE hPrinter; 1964 PSPOOLER_HANDLE pHandle; 1965 PWSTR pDatatype = NULL; 1966 WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 }; 1967 ACCESS_MASK AccessRequired = 0; 1968 1969 TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName, phPrinter, pDefault); 1970 1971 // Sanity check 1972 if (!phPrinter) 1973 { 1974 dwErrorCode = ERROR_INVALID_PARAMETER; 1975 goto Cleanup; 1976 } 1977 1978 // Prepare the additional parameters in the format required by _RpcOpenPrinter 1979 if (pDefault) 1980 { 1981 pDatatype = pDefault->pDatatype; 1982 DevModeContainer.cbBuf = sizeof(DEVMODEW); 1983 DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode; 1984 AccessRequired = pDefault->DesiredAccess; 1985 } 1986 1987 // Do the RPC call 1988 RpcTryExcept 1989 { 1990 dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired); 1991 } 1992 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 1993 { 1994 dwErrorCode = RpcExceptionCode(); 1995 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode); 1996 } 1997 RpcEndExcept; 1998 1999 if (dwErrorCode == ERROR_SUCCESS) 2000 { 2001 // Create a new SPOOLER_HANDLE structure. 2002 pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE)); 2003 if (!pHandle) 2004 { 2005 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2006 ERR("HeapAlloc failed!\n"); 2007 goto Cleanup; 2008 } 2009 2010 pHandle->hPrinter = hPrinter; 2011 pHandle->hSPLFile = INVALID_HANDLE_VALUE; 2012 2013 // Return it as phPrinter. 2014 *phPrinter = (HANDLE)pHandle; 2015 } 2016 2017 Cleanup: 2018 SetLastError(dwErrorCode); 2019 return (dwErrorCode == ERROR_SUCCESS); 2020 } 2021 2022 BOOL WINAPI 2023 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead) 2024 { 2025 DWORD dwErrorCode; 2026 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2027 2028 TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pNoBytesRead); 2029 2030 // Sanity checks. 2031 if (!pHandle) 2032 { 2033 dwErrorCode = ERROR_INVALID_HANDLE; 2034 goto Cleanup; 2035 } 2036 2037 // Do the RPC call 2038 RpcTryExcept 2039 { 2040 dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead); 2041 } 2042 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2043 { 2044 dwErrorCode = RpcExceptionCode(); 2045 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode); 2046 } 2047 RpcEndExcept; 2048 2049 Cleanup: 2050 SetLastError(dwErrorCode); 2051 return (dwErrorCode == ERROR_SUCCESS); 2052 } 2053 2054 BOOL WINAPI 2055 ResetPrinterA(HANDLE hPrinter, PPRINTER_DEFAULTSA pDefault) 2056 { 2057 TRACE("ResetPrinterA(%p, %p)\n", hPrinter, pDefault); 2058 UNIMPLEMENTED; 2059 return FALSE; 2060 } 2061 2062 BOOL WINAPI 2063 ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault) 2064 { 2065 TRACE("ResetPrinterW(%p, %p)\n", hPrinter, pDefault); 2066 UNIMPLEMENTED; 2067 return FALSE; 2068 } 2069 2070 BOOL WINAPI 2071 SetDefaultPrinterA(LPCSTR pszPrinter) 2072 { 2073 BOOL bReturnValue = FALSE; 2074 DWORD cch; 2075 PWSTR pwszPrinter = NULL; 2076 2077 TRACE("SetDefaultPrinterA(%s)\n", pszPrinter); 2078 2079 if (pszPrinter) 2080 { 2081 // Convert pszPrinter to a Unicode string pwszPrinter 2082 cch = strlen(pszPrinter); 2083 2084 pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2085 if (!pwszPrinter) 2086 { 2087 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2088 ERR("HeapAlloc failed!\n"); 2089 goto Cleanup; 2090 } 2091 2092 MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, pwszPrinter, cch + 1); 2093 } 2094 2095 bReturnValue = SetDefaultPrinterW(pwszPrinter); 2096 2097 Cleanup: 2098 if (pwszPrinter) 2099 HeapFree(hProcessHeap, 0, pwszPrinter); 2100 2101 return bReturnValue; 2102 } 2103 2104 BOOL WINAPI 2105 SetDefaultPrinterW(LPCWSTR pszPrinter) 2106 { 2107 const WCHAR wszDevicesKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices"; 2108 2109 DWORD cbDeviceValueData; 2110 DWORD cbPrinterValueData = 0; 2111 DWORD cchPrinter; 2112 DWORD dwErrorCode; 2113 HKEY hDevicesKey = NULL; 2114 HKEY hWindowsKey = NULL; 2115 PWSTR pwszDeviceValueData = NULL; 2116 WCHAR wszPrinter[MAX_PRINTER_NAME + 1]; 2117 2118 TRACE("SetDefaultPrinterW(%S)\n", pszPrinter); 2119 2120 // Open the Devices registry key. 2121 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszDevicesKey, 0, KEY_READ, &hDevicesKey); 2122 if (dwErrorCode != ERROR_SUCCESS) 2123 { 2124 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); 2125 goto Cleanup; 2126 } 2127 2128 // Did the caller give us a printer to set as default? 2129 if (pszPrinter && *pszPrinter) 2130 { 2131 // Check if the given printer exists and query the value data size. 2132 dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, NULL, &cbPrinterValueData); 2133 if (dwErrorCode == ERROR_FILE_NOT_FOUND) 2134 { 2135 dwErrorCode = ERROR_INVALID_PRINTER_NAME; 2136 goto Cleanup; 2137 } 2138 else if (dwErrorCode != ERROR_SUCCESS) 2139 { 2140 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); 2141 goto Cleanup; 2142 } 2143 2144 cchPrinter = wcslen(pszPrinter); 2145 } 2146 else 2147 { 2148 // If there is already a default printer, we're done! 2149 cchPrinter = _countof(wszPrinter); 2150 if (GetDefaultPrinterW(wszPrinter, &cchPrinter)) 2151 { 2152 dwErrorCode = ERROR_SUCCESS; 2153 goto Cleanup; 2154 } 2155 2156 // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size. 2157 cchPrinter = _countof(wszPrinter); 2158 dwErrorCode = (DWORD)RegEnumValueW(hDevicesKey, 0, wszPrinter, &cchPrinter, NULL, NULL, NULL, &cbPrinterValueData); 2159 if (dwErrorCode != ERROR_MORE_DATA) 2160 goto Cleanup; 2161 2162 pszPrinter = wszPrinter; 2163 } 2164 2165 // We now need to query the value data, which has the format "winspool,<Port>:" 2166 // and make "<Printer Name>,winspool,<Port>:" out of it. 2167 // Allocate a buffer large enough for the final data. 2168 cbDeviceValueData = (cchPrinter + 1) * sizeof(WCHAR) + cbPrinterValueData; 2169 pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData); 2170 if (!pwszDeviceValueData) 2171 { 2172 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2173 ERR("HeapAlloc failed!\n"); 2174 goto Cleanup; 2175 } 2176 2177 // Copy the Printer Name and a comma into it. 2178 CopyMemory(pwszDeviceValueData, pszPrinter, cchPrinter * sizeof(WCHAR)); 2179 pwszDeviceValueData[cchPrinter] = L','; 2180 2181 // Append the value data, which has the format "winspool,<Port>:" 2182 dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, (PBYTE)&pwszDeviceValueData[cchPrinter + 1], &cbPrinterValueData); 2183 if (dwErrorCode != ERROR_SUCCESS) 2184 goto Cleanup; 2185 2186 // Open the Windows registry key. 2187 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_SET_VALUE, &hWindowsKey); 2188 if (dwErrorCode != ERROR_SUCCESS) 2189 { 2190 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); 2191 goto Cleanup; 2192 } 2193 2194 // Store our new default printer. 2195 dwErrorCode = (DWORD)RegSetValueExW(hWindowsKey, wszDeviceValue, 0, REG_SZ, (PBYTE)pwszDeviceValueData, cbDeviceValueData); 2196 if (dwErrorCode != ERROR_SUCCESS) 2197 { 2198 ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode); 2199 goto Cleanup; 2200 } 2201 2202 Cleanup: 2203 if (hDevicesKey) 2204 RegCloseKey(hDevicesKey); 2205 2206 if (hWindowsKey) 2207 RegCloseKey(hWindowsKey); 2208 2209 if (pwszDeviceValueData) 2210 HeapFree(hProcessHeap, 0, pwszDeviceValueData); 2211 2212 SetLastError(dwErrorCode); 2213 return (dwErrorCode == ERROR_SUCCESS); 2214 } 2215 2216 BOOL WINAPI 2217 SetPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command) 2218 { 2219 TRACE("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command); 2220 UNIMPLEMENTED; 2221 return FALSE; 2222 } 2223 2224 BOOL WINAPI 2225 SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command) 2226 { 2227 TRACE("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command); 2228 UNIMPLEMENTED; 2229 return FALSE; 2230 } 2231 2232 BOOL WINAPI 2233 SplDriverUnloadComplete(LPWSTR pDriverFile) 2234 { 2235 TRACE("DriverUnloadComplete(%S)\n", pDriverFile); 2236 UNIMPLEMENTED; 2237 return TRUE; // return true for now. 2238 } 2239 2240 DWORD WINAPI 2241 StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) 2242 { 2243 DOC_INFO_1W wDocInfo1 = { 0 }; 2244 DWORD cch; 2245 DWORD dwErrorCode; 2246 DWORD dwReturnValue = 0; 2247 PDOC_INFO_1A pDocInfo1 = (PDOC_INFO_1A)pDocInfo; 2248 2249 TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter, Level, pDocInfo); 2250 2251 // Only check the minimum required for accessing pDocInfo. 2252 // Additional sanity checks are done in StartDocPrinterW. 2253 if (!pDocInfo1) 2254 { 2255 dwErrorCode = ERROR_INVALID_PARAMETER; 2256 goto Cleanup; 2257 } 2258 2259 if (Level != 1) 2260 { 2261 dwErrorCode = ERROR_INVALID_LEVEL; 2262 goto Cleanup; 2263 } 2264 2265 if (pDocInfo1->pDatatype) 2266 { 2267 // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype 2268 cch = strlen(pDocInfo1->pDatatype); 2269 2270 wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2271 if (!wDocInfo1.pDatatype) 2272 { 2273 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2274 ERR("HeapAlloc failed!\n"); 2275 goto Cleanup; 2276 } 2277 2278 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDatatype, -1, wDocInfo1.pDatatype, cch + 1); 2279 } 2280 2281 if (pDocInfo1->pDocName) 2282 { 2283 // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName 2284 cch = strlen(pDocInfo1->pDocName); 2285 2286 wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2287 if (!wDocInfo1.pDocName) 2288 { 2289 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2290 ERR("HeapAlloc failed!\n"); 2291 goto Cleanup; 2292 } 2293 2294 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDocName, -1, wDocInfo1.pDocName, cch + 1); 2295 } 2296 2297 if (pDocInfo1->pOutputFile) 2298 { 2299 // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile 2300 cch = strlen(pDocInfo1->pOutputFile); 2301 2302 wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2303 if (!wDocInfo1.pOutputFile) 2304 { 2305 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2306 ERR("HeapAlloc failed!\n"); 2307 goto Cleanup; 2308 } 2309 2310 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pOutputFile, -1, wDocInfo1.pOutputFile, cch + 1); 2311 } 2312 2313 dwReturnValue = StartDocPrinterW(hPrinter, Level, (PBYTE)&wDocInfo1); 2314 dwErrorCode = GetLastError(); 2315 2316 Cleanup: 2317 if (wDocInfo1.pDatatype) 2318 HeapFree(hProcessHeap, 0, wDocInfo1.pDatatype); 2319 2320 if (wDocInfo1.pDocName) 2321 HeapFree(hProcessHeap, 0, wDocInfo1.pDocName); 2322 2323 if (wDocInfo1.pOutputFile) 2324 HeapFree(hProcessHeap, 0, wDocInfo1.pOutputFile); 2325 2326 SetLastError(dwErrorCode); 2327 return dwReturnValue; 2328 } 2329 2330 DWORD WINAPI 2331 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) 2332 { 2333 DWORD cbAddJobInfo1; 2334 DWORD cbNeeded; 2335 DWORD dwErrorCode; 2336 DWORD dwReturnValue = 0; 2337 PADDJOB_INFO_1W pAddJobInfo1 = NULL; 2338 PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo; 2339 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2340 2341 TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter, Level, pDocInfo); 2342 2343 // Sanity checks. 2344 if (!pHandle) 2345 { 2346 dwErrorCode = ERROR_INVALID_HANDLE; 2347 goto Cleanup; 2348 } 2349 2350 if (!pDocInfo1) 2351 { 2352 dwErrorCode = ERROR_INVALID_PARAMETER; 2353 goto Cleanup; 2354 } 2355 2356 if (Level != 1) 2357 { 2358 dwErrorCode = ERROR_INVALID_LEVEL; 2359 goto Cleanup; 2360 } 2361 2362 if (pHandle->bStartedDoc) 2363 { 2364 dwErrorCode = ERROR_INVALID_PRINTER_STATE; 2365 goto Cleanup; 2366 } 2367 2368 // Check if we want to redirect output into a file. 2369 if (pDocInfo1->pOutputFile) 2370 { 2371 // Do a StartDocPrinter RPC call in this case. 2372 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1); 2373 } 2374 else 2375 { 2376 // Allocate memory for the ADDJOB_INFO_1W structure and a path. 2377 cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR); 2378 pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1); 2379 if (!pAddJobInfo1) 2380 { 2381 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2382 ERR("HeapAlloc failed!\n"); 2383 goto Cleanup; 2384 } 2385 2386 // Try to add a new job. 2387 // This only succeeds if the printer is set to do spooled printing. 2388 if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded)) 2389 { 2390 // Do spooled printing. 2391 dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1); 2392 } 2393 else if (GetLastError() == ERROR_INVALID_ACCESS) 2394 { 2395 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing. 2396 // In this case, we do a StartDocPrinter RPC call. 2397 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1); 2398 } 2399 else 2400 { 2401 dwErrorCode = GetLastError(); 2402 ERR("AddJobW failed with error %lu!\n", dwErrorCode); 2403 goto Cleanup; 2404 } 2405 } 2406 2407 if (dwErrorCode == ERROR_SUCCESS) 2408 { 2409 pHandle->bStartedDoc = TRUE; 2410 dwReturnValue = pHandle->dwJobID; 2411 } 2412 2413 Cleanup: 2414 if (pAddJobInfo1) 2415 HeapFree(hProcessHeap, 0, pAddJobInfo1); 2416 2417 SetLastError(dwErrorCode); 2418 return dwReturnValue; 2419 } 2420 2421 BOOL WINAPI 2422 StartPagePrinter(HANDLE hPrinter) 2423 { 2424 DWORD dwErrorCode; 2425 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2426 2427 TRACE("StartPagePrinter(%p)\n", hPrinter); 2428 2429 // Sanity checks. 2430 if (!pHandle) 2431 { 2432 dwErrorCode = ERROR_INVALID_HANDLE; 2433 goto Cleanup; 2434 } 2435 2436 // Do the RPC call 2437 RpcTryExcept 2438 { 2439 dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter); 2440 } 2441 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2442 { 2443 dwErrorCode = RpcExceptionCode(); 2444 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode); 2445 } 2446 RpcEndExcept; 2447 2448 Cleanup: 2449 SetLastError(dwErrorCode); 2450 return (dwErrorCode == ERROR_SUCCESS); 2451 } 2452 2453 BOOL WINAPI 2454 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten) 2455 { 2456 DWORD dwErrorCode; 2457 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2458 2459 TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pcWritten); 2460 2461 // Sanity checks. 2462 if (!pHandle) 2463 { 2464 dwErrorCode = ERROR_INVALID_HANDLE; 2465 goto Cleanup; 2466 } 2467 2468 if (!pHandle->bStartedDoc) 2469 { 2470 dwErrorCode = ERROR_SPL_NO_STARTDOC; 2471 goto Cleanup; 2472 } 2473 2474 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE) 2475 { 2476 // Write to the spool file. This doesn't need an RPC request. 2477 if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL)) 2478 { 2479 dwErrorCode = GetLastError(); 2480 ERR("WriteFile failed with error %lu!\n", dwErrorCode); 2481 goto Cleanup; 2482 } 2483 2484 dwErrorCode = ERROR_SUCCESS; 2485 } 2486 else 2487 { 2488 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed. 2489 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full. 2490 2491 // Do the RPC call 2492 RpcTryExcept 2493 { 2494 dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten); 2495 } 2496 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2497 { 2498 dwErrorCode = RpcExceptionCode(); 2499 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode); 2500 } 2501 RpcEndExcept; 2502 } 2503 2504 Cleanup: 2505 SetLastError(dwErrorCode); 2506 return (dwErrorCode == ERROR_SUCCESS); 2507 } 2508 2509 BOOL WINAPI 2510 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus) 2511 { 2512 TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus); 2513 return FALSE; 2514 } 2515