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