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 DWORD dwErrorCode; 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 dwErrorCode = 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 dwErrorCode = 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 if (!EnumPrintersW(Flags, pwszName, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned)) 528 { 529 dwErrorCode = GetLastError(); 530 goto Cleanup; 531 } 532 533 /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */ 534 /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */ 535 /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */ 536 537 /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */ 538 ppi1w = (PPRINTER_INFO_1W)pPrinterEnum; 539 ppi2w = (PPRINTER_INFO_2W)pPrinterEnum; 540 ppi4w = (PPRINTER_INFO_4W)pPrinterEnum; 541 ppi5w = (PPRINTER_INFO_5W)pPrinterEnum; 542 /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */ 543 ppi1a = (PPRINTER_INFO_1A)pPrinterEnum; 544 ppi2a = (PPRINTER_INFO_2A)pPrinterEnum; 545 ppi4a = (PPRINTER_INFO_4A)pPrinterEnum; 546 ppi5a = (PPRINTER_INFO_5A)pPrinterEnum; 547 548 for (i = 0; i < *pcReturned; i++) 549 { 550 switch (Level) 551 { 552 case 1: 553 { 554 if (ppi1w[i].pDescription) 555 { 556 // Convert Unicode pDescription to a ANSI string pszDescription. 557 cch = wcslen(ppi1w[i].pDescription); 558 559 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 560 if (!pszDescription) 561 { 562 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 563 ERR("HeapAlloc failed!\n"); 564 goto Cleanup; 565 } 566 567 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pDescription, -1, pszDescription, cch + 1, NULL, NULL); 568 StringCchCopyA(ppi1a[i].pDescription, cch + 1, pszDescription); 569 570 HeapFree(hProcessHeap, 0, pszDescription); 571 } 572 573 if (ppi1w[i].pName) 574 { 575 // Convert Unicode pName to a ANSI string pszName. 576 cch = wcslen(ppi1w[i].pName); 577 578 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 579 if (!pszName) 580 { 581 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 582 ERR("HeapAlloc failed!\n"); 583 goto Cleanup; 584 } 585 586 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pName, -1, pszName, cch + 1, NULL, NULL); 587 StringCchCopyA(ppi1a[i].pName, cch + 1, pszName); 588 589 HeapFree(hProcessHeap, 0, pszName); 590 } 591 592 if (ppi1w[i].pComment) 593 { 594 // Convert Unicode pComment to a ANSI string pszComment. 595 cch = wcslen(ppi1w[i].pComment); 596 597 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 598 if (!pszComment) 599 { 600 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 601 ERR("HeapAlloc failed!\n"); 602 goto Cleanup; 603 } 604 605 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pComment, -1, pszComment, cch + 1, NULL, NULL); 606 StringCchCopyA(ppi1a[i].pComment, cch + 1, pszComment); 607 608 HeapFree(hProcessHeap, 0, pszComment); 609 } 610 break; 611 } 612 613 614 case 2: 615 { 616 if (ppi2w[i].pServerName) 617 { 618 // Convert Unicode pServerName to a ANSI string pszServerName. 619 cch = wcslen(ppi2w[i].pServerName); 620 621 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 622 if (!pszServerName) 623 { 624 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 625 ERR("HeapAlloc failed!\n"); 626 goto Cleanup; 627 } 628 629 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL); 630 StringCchCopyA(ppi2a[i].pServerName, cch + 1, pszServerName); 631 632 HeapFree(hProcessHeap, 0, pszServerName); 633 } 634 635 if (ppi2w[i].pPrinterName) 636 { 637 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 638 cch = wcslen(ppi2w[i].pPrinterName); 639 640 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 641 if (!pszPrinterName) 642 { 643 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 644 ERR("HeapAlloc failed!\n"); 645 goto Cleanup; 646 } 647 648 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 649 StringCchCopyA(ppi2a[i].pPrinterName, cch + 1, pszPrinterName); 650 651 HeapFree(hProcessHeap, 0, pszPrinterName); 652 } 653 654 if (ppi2w[i].pShareName) 655 { 656 // Convert Unicode pShareName to a ANSI string pszShareName. 657 cch = wcslen(ppi2w[i].pShareName); 658 659 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 660 if (!pszShareName) 661 { 662 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 663 ERR("HeapAlloc failed!\n"); 664 goto Cleanup; 665 } 666 667 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pShareName, -1, pszShareName, cch + 1, NULL, NULL); 668 StringCchCopyA(ppi2a[i].pShareName, cch + 1, pszShareName); 669 670 HeapFree(hProcessHeap, 0, pszShareName); 671 } 672 673 if (ppi2w[i].pPortName) 674 { 675 // Convert Unicode pPortName to a ANSI string pszPortName. 676 cch = wcslen(ppi2w[i].pPortName); 677 678 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 679 if (!pszPortName) 680 { 681 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 682 ERR("HeapAlloc failed!\n"); 683 goto Cleanup; 684 } 685 686 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL); 687 StringCchCopyA(ppi2a[i].pPortName, cch + 1, pszPortName); 688 689 HeapFree(hProcessHeap, 0, pszPortName); 690 } 691 692 if (ppi2w[i].pDriverName) 693 { 694 // Convert Unicode pDriverName to a ANSI string pszDriverName. 695 cch = wcslen(ppi2w[i].pDriverName); 696 697 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 698 if (!pszDriverName) 699 { 700 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 701 ERR("HeapAlloc failed!\n"); 702 goto Cleanup; 703 } 704 705 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDriverName, -1, pszDriverName, cch + 1, NULL, NULL); 706 StringCchCopyA(ppi2a[i].pDriverName, cch + 1, pszDriverName); 707 708 HeapFree(hProcessHeap, 0, pszDriverName); 709 } 710 711 if (ppi2w[i].pComment) 712 { 713 // Convert Unicode pComment to a ANSI string pszComment. 714 cch = wcslen(ppi2w[i].pComment); 715 716 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 717 if (!pszComment) 718 { 719 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 720 ERR("HeapAlloc failed!\n"); 721 goto Cleanup; 722 } 723 724 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pComment, -1, pszComment, cch + 1, NULL, NULL); 725 StringCchCopyA(ppi2a[i].pComment, cch + 1, pszComment); 726 727 HeapFree(hProcessHeap, 0, pszComment); 728 } 729 730 if (ppi2w[i].pLocation) 731 { 732 // Convert Unicode pLocation to a ANSI string pszLocation. 733 cch = wcslen(ppi2w[i].pLocation); 734 735 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 736 if (!pszLocation) 737 { 738 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 739 ERR("HeapAlloc failed!\n"); 740 goto Cleanup; 741 } 742 743 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pLocation, -1, pszLocation, cch + 1, NULL, NULL); 744 StringCchCopyA(ppi2a[i].pLocation, cch + 1, pszLocation); 745 746 HeapFree(hProcessHeap, 0, pszLocation); 747 } 748 749 750 if (ppi2w[i].pSepFile) 751 { 752 // Convert Unicode pSepFile to a ANSI string pszSepFile. 753 cch = wcslen(ppi2w[i].pSepFile); 754 755 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 756 if (!pszSepFile) 757 { 758 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 759 ERR("HeapAlloc failed!\n"); 760 goto Cleanup; 761 } 762 763 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pSepFile, -1, pszSepFile, cch + 1, NULL, NULL); 764 StringCchCopyA(ppi2a[i].pSepFile, cch + 1, pszSepFile); 765 766 HeapFree(hProcessHeap, 0, pszSepFile); 767 } 768 769 if (ppi2w[i].pPrintProcessor) 770 { 771 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor. 772 cch = wcslen(ppi2w[i].pPrintProcessor); 773 774 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 775 if (!pszPrintProcessor) 776 { 777 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 778 ERR("HeapAlloc failed!\n"); 779 goto Cleanup; 780 } 781 782 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL); 783 StringCchCopyA(ppi2a[i].pPrintProcessor, cch + 1, pszPrintProcessor); 784 785 HeapFree(hProcessHeap, 0, pszPrintProcessor); 786 } 787 788 789 if (ppi2w[i].pDatatype) 790 { 791 // Convert Unicode pDatatype to a ANSI string pszDatatype. 792 cch = wcslen(ppi2w[i].pDatatype); 793 794 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 795 if (!pszDatatype) 796 { 797 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 798 ERR("HeapAlloc failed!\n"); 799 goto Cleanup; 800 } 801 802 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDatatype, -1, pszDatatype, cch + 1, NULL, NULL); 803 StringCchCopyA(ppi2a[i].pDatatype, cch + 1, pszDatatype); 804 805 HeapFree(hProcessHeap, 0, pszDatatype); 806 } 807 808 if (ppi2w[i].pParameters) 809 { 810 // Convert Unicode pParameters to a ANSI string pszParameters. 811 cch = wcslen(ppi2w[i].pParameters); 812 813 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 814 if (!pszParameters) 815 { 816 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 817 ERR("HeapAlloc failed!\n"); 818 goto Cleanup; 819 } 820 821 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pParameters, -1, pszParameters, cch + 1, NULL, NULL); 822 StringCchCopyA(ppi2a[i].pParameters, cch + 1, pszParameters); 823 824 HeapFree(hProcessHeap, 0, pszParameters); 825 } 826 break; 827 828 } 829 830 case 4: 831 { 832 if (ppi4w[i].pPrinterName) 833 { 834 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 835 cch = wcslen(ppi4w[i].pPrinterName); 836 837 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 838 if (!pszPrinterName) 839 { 840 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 841 ERR("HeapAlloc failed!\n"); 842 goto Cleanup; 843 } 844 845 WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 846 StringCchCopyA(ppi4a[i].pPrinterName, cch + 1, pszPrinterName); 847 848 HeapFree(hProcessHeap, 0, pszPrinterName); 849 } 850 851 if (ppi4w[i].pServerName) 852 { 853 // Convert Unicode pServerName to a ANSI string pszServerName. 854 cch = wcslen(ppi4w[i].pServerName); 855 856 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 857 if (!pszServerName) 858 { 859 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 860 ERR("HeapAlloc failed!\n"); 861 goto Cleanup; 862 } 863 864 WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL); 865 StringCchCopyA(ppi4a[i].pServerName, cch + 1, pszServerName); 866 867 HeapFree(hProcessHeap, 0, pszServerName); 868 } 869 break; 870 } 871 872 case 5: 873 { 874 if (ppi5w[i].pPrinterName) 875 { 876 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 877 cch = wcslen(ppi5w[i].pPrinterName); 878 879 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 880 if (!pszPrinterName) 881 { 882 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 883 ERR("HeapAlloc failed!\n"); 884 goto Cleanup; 885 } 886 887 WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 888 StringCchCopyA(ppi5a[i].pPrinterName, cch + 1, pszPrinterName); 889 890 HeapFree(hProcessHeap, 0, pszPrinterName); 891 } 892 893 if (ppi5w[i].pPortName) 894 { 895 // Convert Unicode pPortName to a ANSI string pszPortName. 896 cch = wcslen(ppi5w[i].pPortName); 897 898 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 899 if (!pszPortName) 900 { 901 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 902 ERR("HeapAlloc failed!\n"); 903 goto Cleanup; 904 } 905 906 WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL); 907 StringCchCopyA(ppi5a[i].pPortName, cch + 1, pszPortName); 908 909 HeapFree(hProcessHeap, 0, pszPortName); 910 } 911 break; 912 } 913 914 } // switch 915 } // for 916 917 dwErrorCode = ERROR_SUCCESS; 918 919 Cleanup: 920 if (pwszName) 921 { 922 HeapFree(hProcessHeap, 0, pwszName); 923 } 924 925 SetLastError(dwErrorCode); 926 return (dwErrorCode == ERROR_SUCCESS); 927 } 928 929 BOOL WINAPI 930 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 931 { 932 DWORD dwErrorCode; 933 934 TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); 935 936 // Dismiss invalid levels already at this point. 937 if (Level == 3 || Level > 5) 938 { 939 dwErrorCode = ERROR_INVALID_LEVEL; 940 goto Cleanup; 941 } 942 943 if (cbBuf && pPrinterEnum) 944 ZeroMemory(pPrinterEnum, cbBuf); 945 946 // Do the RPC call 947 RpcTryExcept 948 { 949 dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); 950 } 951 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 952 { 953 dwErrorCode = RpcExceptionCode(); 954 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode); 955 } 956 RpcEndExcept; 957 958 if (dwErrorCode == ERROR_SUCCESS) 959 { 960 // Replace relative offset addresses in the output by absolute pointers. 961 ASSERT(Level <= 9); 962 MarshallUpStructuresArray(cbBuf, pPrinterEnum, *pcReturned, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE); 963 } 964 965 Cleanup: 966 SetLastError(dwErrorCode); 967 return (dwErrorCode == ERROR_SUCCESS); 968 } 969 970 BOOL WINAPI 971 FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep) 972 { 973 TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter, pBuf, cbBuf, pcWritten, cSleep); 974 UNIMPLEMENTED; 975 return FALSE; 976 } 977 978 BOOL WINAPI 979 GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer) 980 { 981 DWORD dwErrorCode; 982 PWSTR pwszBuffer = NULL; 983 984 TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer, pcchBuffer); 985 986 // Sanity check. 987 if (!pcchBuffer) 988 { 989 dwErrorCode = ERROR_INVALID_PARAMETER; 990 goto Cleanup; 991 } 992 993 // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size. 994 if (pszBuffer && *pcchBuffer) 995 { 996 pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR)); 997 if (!pwszBuffer) 998 { 999 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1000 ERR("HeapAlloc failed!\n"); 1001 goto Cleanup; 1002 } 1003 } 1004 1005 if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer)) 1006 { 1007 dwErrorCode = GetLastError(); 1008 goto Cleanup; 1009 } 1010 1011 // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI. 1012 WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, *pcchBuffer, NULL, NULL); 1013 1014 dwErrorCode = ERROR_SUCCESS; 1015 1016 Cleanup: 1017 if (pwszBuffer) 1018 HeapFree(hProcessHeap, 0, pwszBuffer); 1019 1020 SetLastError(dwErrorCode); 1021 return (dwErrorCode == ERROR_SUCCESS); 1022 } 1023 1024 BOOL WINAPI 1025 GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer) 1026 { 1027 DWORD cbNeeded; 1028 DWORD cchInputBuffer; 1029 DWORD dwErrorCode; 1030 HKEY hWindowsKey = NULL; 1031 PWSTR pwszDevice = NULL; 1032 PWSTR pwszComma; 1033 1034 TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer, pcchBuffer); 1035 1036 // Sanity check. 1037 if (!pcchBuffer) 1038 { 1039 dwErrorCode = ERROR_INVALID_PARAMETER; 1040 goto Cleanup; 1041 } 1042 1043 cchInputBuffer = *pcchBuffer; 1044 1045 // Open the registry key where the default printer for the current user is stored. 1046 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey); 1047 if (dwErrorCode != ERROR_SUCCESS) 1048 { 1049 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); 1050 goto Cleanup; 1051 } 1052 1053 // Determine the size of the required buffer. 1054 dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded); 1055 if (dwErrorCode != ERROR_SUCCESS) 1056 { 1057 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); 1058 goto Cleanup; 1059 } 1060 1061 // Allocate it. 1062 pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded); 1063 if (!pwszDevice) 1064 { 1065 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1066 ERR("HeapAlloc failed!\n"); 1067 goto Cleanup; 1068 } 1069 1070 // Now get the actual value. 1071 dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded); 1072 if (dwErrorCode != ERROR_SUCCESS) 1073 { 1074 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); 1075 goto Cleanup; 1076 } 1077 1078 // We get a string "<Printer Name>,winspool,<Port>:". 1079 // Extract the printer name from it. 1080 pwszComma = wcschr(pwszDevice, L','); 1081 if (!pwszComma) 1082 { 1083 ERR("Found no or invalid default printer: %S!\n", pwszDevice); 1084 dwErrorCode = ERROR_INVALID_NAME; 1085 goto Cleanup; 1086 } 1087 1088 // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer. 1089 *pcchBuffer = pwszComma - pwszDevice + 1; 1090 1091 // Check if the supplied buffer is large enough. 1092 if (cchInputBuffer < *pcchBuffer) 1093 { 1094 dwErrorCode = ERROR_INSUFFICIENT_BUFFER; 1095 goto Cleanup; 1096 } 1097 1098 // Copy the default printer. 1099 *pwszComma = 0; 1100 CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR)); 1101 1102 dwErrorCode = ERROR_SUCCESS; 1103 1104 Cleanup: 1105 if (hWindowsKey) 1106 RegCloseKey(hWindowsKey); 1107 1108 if (pwszDevice) 1109 HeapFree(hProcessHeap, 0, pwszDevice); 1110 1111 SetLastError(dwErrorCode); 1112 return (dwErrorCode == ERROR_SUCCESS); 1113 } 1114 1115 BOOL WINAPI 1116 GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) 1117 { 1118 DWORD dwErrorCode; 1119 PPRINTER_INFO_1A ppi1a = (PPRINTER_INFO_1A)pPrinter; 1120 PPRINTER_INFO_1W ppi1w = (PPRINTER_INFO_1W)pPrinter; 1121 PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter; 1122 PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter; 1123 PPRINTER_INFO_4A ppi4a = (PPRINTER_INFO_4A)pPrinter; 1124 PPRINTER_INFO_4W ppi4w = (PPRINTER_INFO_4W)pPrinter; 1125 PPRINTER_INFO_5A ppi5a = (PPRINTER_INFO_5A)pPrinter; 1126 PPRINTER_INFO_5W ppi5w = (PPRINTER_INFO_5W)pPrinter; 1127 PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter; 1128 PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter; 1129 DWORD cch; 1130 1131 TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 1132 1133 // Check for invalid levels here for early error return. Should be 1-9. 1134 if (Level < 1 || Level > 9) 1135 { 1136 dwErrorCode = ERROR_INVALID_LEVEL; 1137 ERR("Invalid Level!\n"); 1138 goto Cleanup; 1139 } 1140 1141 if (!GetPrinterW(hPrinter, Level, pPrinter, cbBuf, pcbNeeded)) 1142 { 1143 dwErrorCode = GetLastError(); 1144 goto Cleanup; 1145 } 1146 1147 switch (Level) 1148 { 1149 case 1: 1150 { 1151 if (ppi1w->pDescription) 1152 { 1153 PSTR pszDescription; 1154 1155 // Convert Unicode pDescription to a ANSI string pszDescription. 1156 cch = wcslen(ppi1w->pDescription); 1157 1158 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1159 if (!pszDescription) 1160 { 1161 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1162 ERR("HeapAlloc failed!\n"); 1163 goto Cleanup; 1164 } 1165 1166 WideCharToMultiByte(CP_ACP, 0, ppi1w->pDescription, -1, pszDescription, cch + 1, NULL, NULL); 1167 StringCchCopyA(ppi1a->pDescription, cch + 1, pszDescription); 1168 1169 HeapFree(hProcessHeap, 0, pszDescription); 1170 } 1171 1172 if (ppi1w->pName) 1173 { 1174 PSTR pszName; 1175 1176 // Convert Unicode pName to a ANSI string pszName. 1177 cch = wcslen(ppi1w->pName); 1178 1179 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1180 if (!pszName) 1181 { 1182 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1183 ERR("HeapAlloc failed!\n"); 1184 goto Cleanup; 1185 } 1186 1187 WideCharToMultiByte(CP_ACP, 0, ppi1w->pName, -1, pszName, cch + 1, NULL, NULL); 1188 StringCchCopyA(ppi1a->pName, cch + 1, pszName); 1189 1190 HeapFree(hProcessHeap, 0, pszName); 1191 } 1192 1193 if (ppi1w->pComment) 1194 { 1195 PSTR pszComment; 1196 1197 // Convert Unicode pComment to a ANSI string pszComment. 1198 cch = wcslen(ppi1w->pComment); 1199 1200 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1201 if (!pszComment) 1202 { 1203 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1204 ERR("HeapAlloc failed!\n"); 1205 goto Cleanup; 1206 } 1207 1208 WideCharToMultiByte(CP_ACP, 0, ppi1w->pComment, -1, pszComment, cch + 1, NULL, NULL); 1209 StringCchCopyA(ppi1a->pComment, cch + 1, pszComment); 1210 1211 HeapFree(hProcessHeap, 0, pszComment); 1212 } 1213 break; 1214 } 1215 1216 case 2: 1217 { 1218 if (ppi2w->pServerName) 1219 { 1220 PSTR pszServerName; 1221 1222 // Convert Unicode pServerName to a ANSI string pszServerName. 1223 cch = wcslen(ppi2w->pServerName); 1224 1225 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1226 if (!pszServerName) 1227 { 1228 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1229 ERR("HeapAlloc failed!\n"); 1230 goto Cleanup; 1231 } 1232 1233 WideCharToMultiByte(CP_ACP, 0, ppi2w->pServerName, -1, pszServerName, cch + 1, NULL, NULL); 1234 StringCchCopyA(ppi2a->pServerName, cch + 1, pszServerName); 1235 1236 HeapFree(hProcessHeap, 0, pszServerName); 1237 } 1238 1239 if (ppi2w->pPrinterName) 1240 { 1241 PSTR pszPrinterName; 1242 1243 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 1244 cch = wcslen(ppi2w->pPrinterName); 1245 1246 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1247 if (!pszPrinterName) 1248 { 1249 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1250 ERR("HeapAlloc failed!\n"); 1251 goto Cleanup; 1252 } 1253 1254 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 1255 StringCchCopyA(ppi2a->pPrinterName, cch + 1, pszPrinterName); 1256 1257 HeapFree(hProcessHeap, 0, pszPrinterName); 1258 } 1259 1260 if (ppi2w->pShareName) 1261 { 1262 PSTR pszShareName; 1263 1264 // Convert Unicode pShareName to a ANSI string pszShareName. 1265 cch = wcslen(ppi2w->pShareName); 1266 1267 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1268 if (!pszShareName) 1269 { 1270 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1271 ERR("HeapAlloc failed!\n"); 1272 goto Cleanup; 1273 } 1274 1275 WideCharToMultiByte(CP_ACP, 0, ppi2w->pShareName, -1, pszShareName, cch + 1, NULL, NULL); 1276 StringCchCopyA(ppi2a->pShareName, cch + 1, pszShareName); 1277 1278 HeapFree(hProcessHeap, 0, pszShareName); 1279 } 1280 1281 if (ppi2w->pPortName) 1282 { 1283 PSTR pszPortName; 1284 1285 // Convert Unicode pPortName to a ANSI string pszPortName. 1286 cch = wcslen(ppi2w->pPortName); 1287 1288 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1289 if (!pszPortName) 1290 { 1291 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1292 ERR("HeapAlloc failed!\n"); 1293 goto Cleanup; 1294 } 1295 1296 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPortName, -1, pszPortName, cch + 1, NULL, NULL); 1297 StringCchCopyA(ppi2a->pPortName, cch + 1, pszPortName); 1298 1299 HeapFree(hProcessHeap, 0, pszPortName); 1300 } 1301 1302 if (ppi2w->pDriverName) 1303 { 1304 PSTR pszDriverName; 1305 1306 // Convert Unicode pDriverName to a ANSI string pszDriverName. 1307 cch = wcslen(ppi2w->pDriverName); 1308 1309 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1310 if (!pszDriverName) 1311 { 1312 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1313 ERR("HeapAlloc failed!\n"); 1314 goto Cleanup; 1315 } 1316 1317 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDriverName, -1, pszDriverName, cch + 1, NULL, NULL); 1318 StringCchCopyA(ppi2a->pDriverName, cch + 1, pszDriverName); 1319 1320 HeapFree(hProcessHeap, 0, pszDriverName); 1321 } 1322 1323 if (ppi2w->pComment) 1324 { 1325 PSTR pszComment; 1326 1327 // Convert Unicode pComment to a ANSI string pszComment. 1328 cch = wcslen(ppi2w->pComment); 1329 1330 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1331 if (!pszComment) 1332 { 1333 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1334 ERR("HeapAlloc failed!\n"); 1335 goto Cleanup; 1336 } 1337 1338 WideCharToMultiByte(CP_ACP, 0, ppi2w->pComment, -1, pszComment, cch + 1, NULL, NULL); 1339 StringCchCopyA(ppi2a->pComment, cch + 1, pszComment); 1340 1341 HeapFree(hProcessHeap, 0, pszComment); 1342 } 1343 1344 if (ppi2w->pLocation) 1345 { 1346 PSTR pszLocation; 1347 1348 // Convert Unicode pLocation to a ANSI string pszLocation. 1349 cch = wcslen(ppi2w->pLocation); 1350 1351 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1352 if (!pszLocation) 1353 { 1354 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1355 ERR("HeapAlloc failed!\n"); 1356 goto Cleanup; 1357 } 1358 1359 WideCharToMultiByte(CP_ACP, 0, ppi2w->pLocation, -1, pszLocation, cch + 1, NULL, NULL); 1360 StringCchCopyA(ppi2a->pLocation, cch + 1, pszLocation); 1361 1362 HeapFree(hProcessHeap, 0, pszLocation); 1363 } 1364 1365 if (ppi2w->pSepFile) 1366 { 1367 PSTR pszSepFile; 1368 1369 // Convert Unicode pSepFile to a ANSI string pszSepFile. 1370 cch = wcslen(ppi2w->pSepFile); 1371 1372 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1373 if (!pszSepFile) 1374 { 1375 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1376 ERR("HeapAlloc failed!\n"); 1377 goto Cleanup; 1378 } 1379 1380 WideCharToMultiByte(CP_ACP, 0, ppi2w->pSepFile, -1, pszSepFile, cch + 1, NULL, NULL); 1381 StringCchCopyA(ppi2a->pSepFile, cch + 1, pszSepFile); 1382 1383 HeapFree(hProcessHeap, 0, pszSepFile); 1384 } 1385 1386 if (ppi2w->pPrintProcessor) 1387 { 1388 PSTR pszPrintProcessor; 1389 1390 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor. 1391 cch = wcslen(ppi2w->pPrintProcessor); 1392 1393 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1394 if (!pszPrintProcessor) 1395 { 1396 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1397 ERR("HeapAlloc failed!\n"); 1398 goto Cleanup; 1399 } 1400 1401 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL); 1402 StringCchCopyA(ppi2a->pPrintProcessor, cch + 1, pszPrintProcessor); 1403 1404 HeapFree(hProcessHeap, 0, pszPrintProcessor); 1405 } 1406 1407 if (ppi2w->pDatatype) 1408 { 1409 PSTR pszDatatype; 1410 1411 // Convert Unicode pDatatype to a ANSI string pszDatatype. 1412 cch = wcslen(ppi2w->pDatatype); 1413 1414 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1415 if (!pszDatatype) 1416 { 1417 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1418 ERR("HeapAlloc failed!\n"); 1419 goto Cleanup; 1420 } 1421 1422 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDatatype, -1, pszDatatype, cch + 1, NULL, NULL); 1423 StringCchCopyA(ppi2a->pDatatype, cch + 1, pszDatatype); 1424 1425 HeapFree(hProcessHeap, 0, pszDatatype); 1426 } 1427 1428 if (ppi2w->pParameters) 1429 { 1430 PSTR pszParameters; 1431 1432 // Convert Unicode pParameters to a ANSI string pszParameters. 1433 cch = wcslen(ppi2w->pParameters); 1434 1435 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1436 if (!pszParameters) 1437 { 1438 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1439 ERR("HeapAlloc failed!\n"); 1440 goto Cleanup; 1441 } 1442 1443 WideCharToMultiByte(CP_ACP, 0, ppi2w->pParameters, -1, pszParameters, cch + 1, NULL, NULL); 1444 StringCchCopyA(ppi2a->pParameters, cch + 1, pszParameters); 1445 1446 HeapFree(hProcessHeap, 0, pszParameters); 1447 } 1448 break; 1449 } 1450 1451 case 4: 1452 { 1453 if (ppi4w->pPrinterName) 1454 { 1455 PSTR pszPrinterName; 1456 1457 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 1458 cch = wcslen(ppi4w->pPrinterName); 1459 1460 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1461 if (!pszPrinterName) 1462 { 1463 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1464 ERR("HeapAlloc failed!\n"); 1465 goto Cleanup; 1466 } 1467 1468 WideCharToMultiByte(CP_ACP, 0, ppi4w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 1469 StringCchCopyA(ppi4a->pPrinterName, cch + 1, pszPrinterName); 1470 1471 HeapFree(hProcessHeap, 0, pszPrinterName); 1472 } 1473 1474 if (ppi4w->pServerName) 1475 { 1476 PSTR pszServerName; 1477 1478 // Convert Unicode pServerName to a ANSI string pszServerName. 1479 cch = wcslen(ppi4w->pServerName); 1480 1481 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1482 if (!pszServerName) 1483 { 1484 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1485 ERR("HeapAlloc failed!\n"); 1486 goto Cleanup; 1487 } 1488 1489 WideCharToMultiByte(CP_ACP, 0, ppi4w->pServerName, -1, pszServerName, cch + 1, NULL, NULL); 1490 StringCchCopyA(ppi4a->pServerName, cch + 1, pszServerName); 1491 1492 HeapFree(hProcessHeap, 0, pszServerName); 1493 } 1494 break; 1495 } 1496 1497 case 5: 1498 { 1499 if (ppi5w->pPrinterName) 1500 { 1501 PSTR pszPrinterName; 1502 1503 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 1504 cch = wcslen(ppi5w->pPrinterName); 1505 1506 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1507 if (!pszPrinterName) 1508 { 1509 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1510 ERR("HeapAlloc failed!\n"); 1511 goto Cleanup; 1512 } 1513 1514 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 1515 StringCchCopyA(ppi5a->pPrinterName, cch + 1, pszPrinterName); 1516 1517 HeapFree(hProcessHeap, 0, pszPrinterName); 1518 } 1519 1520 if (ppi5w->pPortName) 1521 { 1522 PSTR pszPortName; 1523 1524 // Convert Unicode pPortName to a ANSI string pszPortName. 1525 cch = wcslen(ppi5w->pPortName); 1526 1527 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1528 if (!pszPortName) 1529 { 1530 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1531 ERR("HeapAlloc failed!\n"); 1532 goto Cleanup; 1533 } 1534 1535 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPortName, -1, pszPortName, cch + 1, NULL, NULL); 1536 StringCchCopyA(ppi5a->pPortName, cch + 1, pszPortName); 1537 1538 HeapFree(hProcessHeap, 0, pszPortName); 1539 } 1540 break; 1541 } 1542 1543 case 7: 1544 { 1545 if (ppi7w->pszObjectGUID) 1546 { 1547 PSTR pszaObjectGUID; 1548 1549 // Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID. 1550 cch = wcslen(ppi7w->pszObjectGUID); 1551 1552 pszaObjectGUID = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1553 if (!pszaObjectGUID) 1554 { 1555 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1556 ERR("HeapAlloc failed!\n"); 1557 goto Cleanup; 1558 } 1559 1560 WideCharToMultiByte(CP_ACP, 0, ppi7w->pszObjectGUID, -1, pszaObjectGUID, cch + 1, NULL, NULL); 1561 StringCchCopyA(ppi7a->pszObjectGUID, cch + 1, pszaObjectGUID); 1562 1563 HeapFree(hProcessHeap, 0, pszaObjectGUID); 1564 } 1565 break; 1566 } 1567 } // switch 1568 1569 dwErrorCode = ERROR_SUCCESS; 1570 1571 Cleanup: 1572 SetLastError(dwErrorCode); 1573 return (dwErrorCode == ERROR_SUCCESS); 1574 } 1575 1576 BOOL WINAPI 1577 GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) 1578 { 1579 DWORD dwErrorCode; 1580 /* 1581 * We are mapping multiple different pointers to the same pDriverInfo pointer here so that 1582 * we can use the same incoming pointer for different Levels 1583 */ 1584 PDRIVER_INFO_1W pdi1w = (PDRIVER_INFO_1W)pDriverInfo; 1585 PDRIVER_INFO_2W pdi2w = (PDRIVER_INFO_2W)pDriverInfo; 1586 PDRIVER_INFO_3W pdi3w = (PDRIVER_INFO_3W)pDriverInfo; 1587 PDRIVER_INFO_4W pdi4w = (PDRIVER_INFO_4W)pDriverInfo; 1588 PDRIVER_INFO_5W pdi5w = (PDRIVER_INFO_5W)pDriverInfo; 1589 PDRIVER_INFO_6W pdi6w = (PDRIVER_INFO_6W)pDriverInfo; 1590 1591 DWORD cch; 1592 PWSTR pwszEnvironment = NULL; 1593 1594 TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); 1595 1596 // Check for invalid levels here for early error return. Should be 1-6. 1597 if (Level < 1 || Level > 6) 1598 { 1599 dwErrorCode = ERROR_INVALID_LEVEL; 1600 ERR("Invalid Level!\n"); 1601 goto Cleanup; 1602 } 1603 1604 if (pEnvironment) 1605 { 1606 // Convert pEnvironment to a Unicode string pwszEnvironment. 1607 cch = strlen(pEnvironment); 1608 1609 pwszEnvironment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 1610 if (!pwszEnvironment) 1611 { 1612 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1613 ERR("HeapAlloc failed!\n"); 1614 goto Cleanup; 1615 } 1616 1617 MultiByteToWideChar(CP_ACP, 0, pEnvironment, -1, pwszEnvironment, cch + 1); 1618 } 1619 1620 if (!GetPrinterDriverW(hPrinter, pwszEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded)) 1621 { 1622 dwErrorCode = GetLastError(); 1623 goto Cleanup; 1624 } 1625 1626 // Do Unicode to ANSI conversions for strings based on Level 1627 switch (Level) 1628 { 1629 case 1: 1630 { 1631 dwErrorCode = UnicodeToAnsiInPlace(pdi1w->pName); 1632 if (dwErrorCode != ERROR_SUCCESS) 1633 { 1634 goto Cleanup; 1635 } 1636 1637 break; 1638 } 1639 1640 case 2: 1641 { 1642 dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pName); 1643 if (dwErrorCode != ERROR_SUCCESS) 1644 { 1645 goto Cleanup; 1646 } 1647 1648 dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pEnvironment); 1649 if (dwErrorCode != ERROR_SUCCESS) 1650 { 1651 goto Cleanup; 1652 } 1653 1654 dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pDriverPath); 1655 if (dwErrorCode != ERROR_SUCCESS) 1656 { 1657 goto Cleanup; 1658 } 1659 1660 dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pDataFile); 1661 if (dwErrorCode != ERROR_SUCCESS) 1662 { 1663 goto Cleanup; 1664 } 1665 1666 dwErrorCode = UnicodeToAnsiInPlace(pdi2w->pConfigFile); 1667 if (dwErrorCode != ERROR_SUCCESS) 1668 { 1669 goto Cleanup; 1670 } 1671 1672 break; 1673 } 1674 1675 case 3: 1676 { 1677 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pName); 1678 if (dwErrorCode != ERROR_SUCCESS) 1679 { 1680 goto Cleanup; 1681 } 1682 1683 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pEnvironment); 1684 if (dwErrorCode != ERROR_SUCCESS) 1685 { 1686 goto Cleanup; 1687 } 1688 1689 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDriverPath); 1690 if (dwErrorCode != ERROR_SUCCESS) 1691 { 1692 goto Cleanup; 1693 } 1694 1695 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDataFile); 1696 if (dwErrorCode != ERROR_SUCCESS) 1697 { 1698 goto Cleanup; 1699 } 1700 1701 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pConfigFile); 1702 if (dwErrorCode != ERROR_SUCCESS) 1703 { 1704 goto Cleanup; 1705 } 1706 1707 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pHelpFile); 1708 if (dwErrorCode != ERROR_SUCCESS) 1709 { 1710 goto Cleanup; 1711 } 1712 1713 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDependentFiles); 1714 if (dwErrorCode != ERROR_SUCCESS) 1715 { 1716 goto Cleanup; 1717 } 1718 1719 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pMonitorName); 1720 if (dwErrorCode != ERROR_SUCCESS) 1721 { 1722 goto Cleanup; 1723 } 1724 1725 dwErrorCode = UnicodeToAnsiInPlace(pdi3w->pDefaultDataType); 1726 if (dwErrorCode != ERROR_SUCCESS) 1727 { 1728 goto Cleanup; 1729 } 1730 1731 break; 1732 } 1733 1734 case 4: 1735 { 1736 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pName); 1737 if (dwErrorCode != ERROR_SUCCESS) 1738 { 1739 goto Cleanup; 1740 } 1741 1742 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pEnvironment); 1743 if (dwErrorCode != ERROR_SUCCESS) 1744 { 1745 goto Cleanup; 1746 } 1747 1748 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDriverPath); 1749 if (dwErrorCode != ERROR_SUCCESS) 1750 { 1751 goto Cleanup; 1752 } 1753 1754 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDataFile); 1755 if (dwErrorCode != ERROR_SUCCESS) 1756 { 1757 goto Cleanup; 1758 } 1759 1760 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pConfigFile); 1761 if (dwErrorCode != ERROR_SUCCESS) 1762 { 1763 goto Cleanup; 1764 } 1765 1766 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pHelpFile); 1767 if (dwErrorCode != ERROR_SUCCESS) 1768 { 1769 goto Cleanup; 1770 } 1771 1772 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDependentFiles); 1773 if (dwErrorCode != ERROR_SUCCESS) 1774 { 1775 goto Cleanup; 1776 } 1777 1778 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pMonitorName); 1779 if (dwErrorCode != ERROR_SUCCESS) 1780 { 1781 goto Cleanup; 1782 } 1783 1784 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pDefaultDataType); 1785 if (dwErrorCode != ERROR_SUCCESS) 1786 { 1787 goto Cleanup; 1788 } 1789 1790 dwErrorCode = UnicodeToAnsiInPlace(pdi4w->pszzPreviousNames); 1791 if (dwErrorCode != ERROR_SUCCESS) 1792 { 1793 goto Cleanup; 1794 } 1795 1796 break; 1797 } 1798 1799 case 5: 1800 { 1801 dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pName); 1802 if (dwErrorCode != ERROR_SUCCESS) 1803 { 1804 goto Cleanup; 1805 } 1806 1807 dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pEnvironment); 1808 if (dwErrorCode != ERROR_SUCCESS) 1809 { 1810 goto Cleanup; 1811 } 1812 1813 dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pDriverPath); 1814 if (dwErrorCode != ERROR_SUCCESS) 1815 { 1816 goto Cleanup; 1817 } 1818 1819 dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pDataFile); 1820 if (dwErrorCode != ERROR_SUCCESS) 1821 { 1822 goto Cleanup; 1823 } 1824 1825 dwErrorCode = UnicodeToAnsiInPlace(pdi5w->pConfigFile); 1826 if (dwErrorCode != ERROR_SUCCESS) 1827 { 1828 goto Cleanup; 1829 } 1830 1831 break; 1832 } 1833 1834 case 6: 1835 { 1836 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pName); 1837 if (dwErrorCode != ERROR_SUCCESS) 1838 { 1839 goto Cleanup; 1840 } 1841 1842 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pEnvironment); 1843 if (dwErrorCode != ERROR_SUCCESS) 1844 { 1845 goto Cleanup; 1846 } 1847 1848 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDriverPath); 1849 if (dwErrorCode != ERROR_SUCCESS) 1850 { 1851 goto Cleanup; 1852 } 1853 1854 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDataFile); 1855 if (dwErrorCode != ERROR_SUCCESS) 1856 { 1857 goto Cleanup; 1858 } 1859 1860 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pConfigFile); 1861 if (dwErrorCode != ERROR_SUCCESS) 1862 { 1863 goto Cleanup; 1864 } 1865 1866 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pHelpFile); 1867 if (dwErrorCode != ERROR_SUCCESS) 1868 { 1869 goto Cleanup; 1870 } 1871 1872 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDependentFiles); 1873 if (dwErrorCode != ERROR_SUCCESS) 1874 { 1875 goto Cleanup; 1876 } 1877 1878 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pMonitorName); 1879 if (dwErrorCode != ERROR_SUCCESS) 1880 { 1881 goto Cleanup; 1882 } 1883 1884 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pDefaultDataType); 1885 if (dwErrorCode != ERROR_SUCCESS) 1886 { 1887 goto Cleanup; 1888 } 1889 1890 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszzPreviousNames); 1891 if (dwErrorCode != ERROR_SUCCESS) 1892 { 1893 goto Cleanup; 1894 } 1895 1896 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszMfgName); 1897 if (dwErrorCode != ERROR_SUCCESS) 1898 { 1899 goto Cleanup; 1900 } 1901 1902 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszOEMUrl); 1903 if (dwErrorCode != ERROR_SUCCESS) 1904 { 1905 goto Cleanup; 1906 } 1907 1908 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszHardwareID); 1909 if (dwErrorCode != ERROR_SUCCESS) 1910 { 1911 goto Cleanup; 1912 } 1913 1914 dwErrorCode = UnicodeToAnsiInPlace(pdi6w->pszProvider); 1915 if (dwErrorCode != ERROR_SUCCESS) 1916 { 1917 goto Cleanup; 1918 } 1919 } 1920 } 1921 1922 dwErrorCode = ERROR_SUCCESS; 1923 1924 Cleanup: 1925 if (pwszEnvironment) 1926 { 1927 HeapFree(hProcessHeap, 0, pwszEnvironment); 1928 } 1929 1930 SetLastError(dwErrorCode); 1931 return (dwErrorCode == ERROR_SUCCESS); 1932 } 1933 1934 BOOL WINAPI 1935 GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded) 1936 { 1937 DWORD dwErrorCode; 1938 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 1939 1940 TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); 1941 1942 // Sanity checks. 1943 if (!pHandle) 1944 { 1945 dwErrorCode = ERROR_INVALID_HANDLE; 1946 goto Cleanup; 1947 } 1948 1949 // Dismiss invalid levels already at this point. 1950 if (Level > 8 || Level < 1) 1951 { 1952 dwErrorCode = ERROR_INVALID_LEVEL; 1953 goto Cleanup; 1954 } 1955 1956 if (cbBuf && pDriverInfo) 1957 ZeroMemory(pDriverInfo, cbBuf); 1958 1959 // Do the RPC call 1960 RpcTryExcept 1961 { 1962 dwErrorCode = _RpcGetPrinterDriver(pHandle->hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded); 1963 } 1964 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 1965 { 1966 dwErrorCode = RpcExceptionCode(); 1967 ERR("_RpcGetPrinterDriver failed with exception code %lu!\n", dwErrorCode); 1968 } 1969 RpcEndExcept; 1970 1971 if (dwErrorCode == ERROR_SUCCESS) 1972 { 1973 // Replace relative offset addresses in the output by absolute pointers. 1974 ASSERT(Level <= 5); 1975 MarshallUpStructure(cbBuf, pDriverInfo, pPrinterDriverMarshalling[Level]->pInfo, pPrinterDriverMarshalling[Level]->cbStructureSize, TRUE); 1976 } 1977 1978 Cleanup: 1979 SetLastError(dwErrorCode); 1980 return (dwErrorCode == ERROR_SUCCESS); 1981 } 1982 1983 BOOL WINAPI 1984 GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) 1985 { 1986 DWORD dwErrorCode; 1987 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 1988 1989 TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 1990 1991 // Sanity checks. 1992 if (!pHandle) 1993 { 1994 dwErrorCode = ERROR_INVALID_HANDLE; 1995 goto Cleanup; 1996 } 1997 1998 // Dismiss invalid levels already at this point. 1999 if (Level > 9) 2000 { 2001 dwErrorCode = ERROR_INVALID_LEVEL; 2002 goto Cleanup; 2003 } 2004 2005 if (cbBuf && pPrinter) 2006 ZeroMemory(pPrinter, cbBuf); 2007 2008 // Do the RPC call 2009 RpcTryExcept 2010 { 2011 dwErrorCode = _RpcGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 2012 } 2013 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2014 { 2015 dwErrorCode = RpcExceptionCode(); 2016 ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode); 2017 } 2018 RpcEndExcept; 2019 2020 if (dwErrorCode == ERROR_SUCCESS) 2021 { 2022 // Replace relative offset addresses in the output by absolute pointers. 2023 ASSERT(Level <= 9); 2024 MarshallUpStructure(cbBuf, pPrinter, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE); 2025 } 2026 2027 Cleanup: 2028 SetLastError(dwErrorCode); 2029 return (dwErrorCode == ERROR_SUCCESS); 2030 } 2031 2032 BOOL WINAPI 2033 OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault) 2034 { 2035 BOOL bReturnValue = FALSE; 2036 DWORD cch; 2037 PWSTR pwszPrinterName = NULL; 2038 PRINTER_DEFAULTSW wDefault = { 0 }; 2039 2040 TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName, phPrinter, pDefault); 2041 2042 if (pPrinterName) 2043 { 2044 // Convert pPrinterName to a Unicode string pwszPrinterName 2045 cch = strlen(pPrinterName); 2046 2047 pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2048 if (!pwszPrinterName) 2049 { 2050 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2051 ERR("HeapAlloc failed!\n"); 2052 goto Cleanup; 2053 } 2054 2055 MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, cch + 1); 2056 } 2057 2058 if (pDefault) 2059 { 2060 wDefault.DesiredAccess = pDefault->DesiredAccess; 2061 2062 if (pDefault->pDatatype) 2063 { 2064 // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype 2065 cch = strlen(pDefault->pDatatype); 2066 2067 wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2068 if (!wDefault.pDatatype) 2069 { 2070 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2071 ERR("HeapAlloc failed!\n"); 2072 goto Cleanup; 2073 } 2074 2075 MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, wDefault.pDatatype, cch + 1); 2076 } 2077 2078 if (pDefault->pDevMode) 2079 wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode); 2080 } 2081 2082 bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault); 2083 2084 Cleanup: 2085 if (wDefault.pDatatype) 2086 HeapFree(hProcessHeap, 0, wDefault.pDatatype); 2087 2088 if (wDefault.pDevMode) 2089 HeapFree(hProcessHeap, 0, wDefault.pDevMode); 2090 2091 if (pwszPrinterName) 2092 HeapFree(hProcessHeap, 0, pwszPrinterName); 2093 2094 return bReturnValue; 2095 } 2096 2097 BOOL WINAPI 2098 OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault) 2099 { 2100 DWORD dwErrorCode; 2101 HANDLE hPrinter; 2102 PSPOOLER_HANDLE pHandle; 2103 PWSTR pDatatype = NULL; 2104 WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 }; 2105 ACCESS_MASK AccessRequired = 0; 2106 2107 TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName, phPrinter, pDefault); 2108 2109 // Sanity check 2110 if (!phPrinter) 2111 { 2112 dwErrorCode = ERROR_INVALID_PARAMETER; 2113 goto Cleanup; 2114 } 2115 2116 // Prepare the additional parameters in the format required by _RpcOpenPrinter 2117 if (pDefault) 2118 { 2119 pDatatype = pDefault->pDatatype; 2120 DevModeContainer.cbBuf = sizeof(DEVMODEW); 2121 DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode; 2122 AccessRequired = pDefault->DesiredAccess; 2123 } 2124 2125 // Do the RPC call 2126 RpcTryExcept 2127 { 2128 dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired); 2129 } 2130 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2131 { 2132 dwErrorCode = RpcExceptionCode(); 2133 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode); 2134 } 2135 RpcEndExcept; 2136 2137 if (dwErrorCode == ERROR_SUCCESS) 2138 { 2139 // Create a new SPOOLER_HANDLE structure. 2140 pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE)); 2141 if (!pHandle) 2142 { 2143 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2144 ERR("HeapAlloc failed!\n"); 2145 goto Cleanup; 2146 } 2147 2148 pHandle->hPrinter = hPrinter; 2149 pHandle->hSPLFile = INVALID_HANDLE_VALUE; 2150 2151 // Return it as phPrinter. 2152 *phPrinter = (HANDLE)pHandle; 2153 } 2154 2155 Cleanup: 2156 SetLastError(dwErrorCode); 2157 return (dwErrorCode == ERROR_SUCCESS); 2158 } 2159 2160 BOOL WINAPI 2161 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead) 2162 { 2163 DWORD dwErrorCode; 2164 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2165 2166 TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pNoBytesRead); 2167 2168 // Sanity checks. 2169 if (!pHandle) 2170 { 2171 dwErrorCode = ERROR_INVALID_HANDLE; 2172 goto Cleanup; 2173 } 2174 2175 // Do the RPC call 2176 RpcTryExcept 2177 { 2178 dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead); 2179 } 2180 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2181 { 2182 dwErrorCode = RpcExceptionCode(); 2183 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode); 2184 } 2185 RpcEndExcept; 2186 2187 Cleanup: 2188 SetLastError(dwErrorCode); 2189 return (dwErrorCode == ERROR_SUCCESS); 2190 } 2191 2192 BOOL WINAPI 2193 ResetPrinterA(HANDLE hPrinter, PPRINTER_DEFAULTSA pDefault) 2194 { 2195 TRACE("ResetPrinterA(%p, %p)\n", hPrinter, pDefault); 2196 UNIMPLEMENTED; 2197 return FALSE; 2198 } 2199 2200 BOOL WINAPI 2201 ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault) 2202 { 2203 TRACE("ResetPrinterW(%p, %p)\n", hPrinter, pDefault); 2204 UNIMPLEMENTED; 2205 return FALSE; 2206 } 2207 2208 BOOL WINAPI 2209 SetDefaultPrinterA(LPCSTR pszPrinter) 2210 { 2211 BOOL bReturnValue = FALSE; 2212 DWORD cch; 2213 PWSTR pwszPrinter = NULL; 2214 2215 TRACE("SetDefaultPrinterA(%s)\n", pszPrinter); 2216 2217 if (pszPrinter) 2218 { 2219 // Convert pszPrinter to a Unicode string pwszPrinter 2220 cch = strlen(pszPrinter); 2221 2222 pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2223 if (!pwszPrinter) 2224 { 2225 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2226 ERR("HeapAlloc failed!\n"); 2227 goto Cleanup; 2228 } 2229 2230 MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, pwszPrinter, cch + 1); 2231 } 2232 2233 bReturnValue = SetDefaultPrinterW(pwszPrinter); 2234 2235 Cleanup: 2236 if (pwszPrinter) 2237 HeapFree(hProcessHeap, 0, pwszPrinter); 2238 2239 return bReturnValue; 2240 } 2241 2242 BOOL WINAPI 2243 SetDefaultPrinterW(LPCWSTR pszPrinter) 2244 { 2245 const WCHAR wszDevicesKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices"; 2246 2247 DWORD cbDeviceValueData; 2248 DWORD cbPrinterValueData = 0; 2249 DWORD cchPrinter; 2250 DWORD dwErrorCode; 2251 HKEY hDevicesKey = NULL; 2252 HKEY hWindowsKey = NULL; 2253 PWSTR pwszDeviceValueData = NULL; 2254 WCHAR wszPrinter[MAX_PRINTER_NAME + 1]; 2255 2256 TRACE("SetDefaultPrinterW(%S)\n", pszPrinter); 2257 2258 // Open the Devices registry key. 2259 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszDevicesKey, 0, KEY_READ, &hDevicesKey); 2260 if (dwErrorCode != ERROR_SUCCESS) 2261 { 2262 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); 2263 goto Cleanup; 2264 } 2265 2266 // Did the caller give us a printer to set as default? 2267 if (pszPrinter && *pszPrinter) 2268 { 2269 // Check if the given printer exists and query the value data size. 2270 dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, NULL, &cbPrinterValueData); 2271 if (dwErrorCode == ERROR_FILE_NOT_FOUND) 2272 { 2273 dwErrorCode = ERROR_INVALID_PRINTER_NAME; 2274 goto Cleanup; 2275 } 2276 else if (dwErrorCode != ERROR_SUCCESS) 2277 { 2278 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); 2279 goto Cleanup; 2280 } 2281 2282 cchPrinter = wcslen(pszPrinter); 2283 } 2284 else 2285 { 2286 // If there is already a default printer, we're done! 2287 cchPrinter = _countof(wszPrinter); 2288 if (GetDefaultPrinterW(wszPrinter, &cchPrinter)) 2289 { 2290 dwErrorCode = ERROR_SUCCESS; 2291 goto Cleanup; 2292 } 2293 2294 // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size. 2295 cchPrinter = _countof(wszPrinter); 2296 dwErrorCode = (DWORD)RegEnumValueW(hDevicesKey, 0, wszPrinter, &cchPrinter, NULL, NULL, NULL, &cbPrinterValueData); 2297 if (dwErrorCode != ERROR_MORE_DATA) 2298 goto Cleanup; 2299 2300 pszPrinter = wszPrinter; 2301 } 2302 2303 // We now need to query the value data, which has the format "winspool,<Port>:" 2304 // and make "<Printer Name>,winspool,<Port>:" out of it. 2305 // Allocate a buffer large enough for the final data. 2306 cbDeviceValueData = (cchPrinter + 1) * sizeof(WCHAR) + cbPrinterValueData; 2307 pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData); 2308 if (!pwszDeviceValueData) 2309 { 2310 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2311 ERR("HeapAlloc failed!\n"); 2312 goto Cleanup; 2313 } 2314 2315 // Copy the Printer Name and a comma into it. 2316 CopyMemory(pwszDeviceValueData, pszPrinter, cchPrinter * sizeof(WCHAR)); 2317 pwszDeviceValueData[cchPrinter] = L','; 2318 2319 // Append the value data, which has the format "winspool,<Port>:" 2320 dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, (PBYTE)&pwszDeviceValueData[cchPrinter + 1], &cbPrinterValueData); 2321 if (dwErrorCode != ERROR_SUCCESS) 2322 goto Cleanup; 2323 2324 // Open the Windows registry key. 2325 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_SET_VALUE, &hWindowsKey); 2326 if (dwErrorCode != ERROR_SUCCESS) 2327 { 2328 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); 2329 goto Cleanup; 2330 } 2331 2332 // Store our new default printer. 2333 dwErrorCode = (DWORD)RegSetValueExW(hWindowsKey, wszDeviceValue, 0, REG_SZ, (PBYTE)pwszDeviceValueData, cbDeviceValueData); 2334 if (dwErrorCode != ERROR_SUCCESS) 2335 { 2336 ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode); 2337 goto Cleanup; 2338 } 2339 2340 Cleanup: 2341 if (hDevicesKey) 2342 RegCloseKey(hDevicesKey); 2343 2344 if (hWindowsKey) 2345 RegCloseKey(hWindowsKey); 2346 2347 if (pwszDeviceValueData) 2348 HeapFree(hProcessHeap, 0, pwszDeviceValueData); 2349 2350 SetLastError(dwErrorCode); 2351 return (dwErrorCode == ERROR_SUCCESS); 2352 } 2353 2354 BOOL WINAPI 2355 SetPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command) 2356 { 2357 TRACE("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command); 2358 UNIMPLEMENTED; 2359 return FALSE; 2360 } 2361 2362 BOOL WINAPI 2363 SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command) 2364 { 2365 TRACE("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command); 2366 UNIMPLEMENTED; 2367 return FALSE; 2368 } 2369 2370 BOOL WINAPI 2371 SplDriverUnloadComplete(LPWSTR pDriverFile) 2372 { 2373 TRACE("DriverUnloadComplete(%S)\n", pDriverFile); 2374 UNIMPLEMENTED; 2375 return TRUE; // return true for now. 2376 } 2377 2378 DWORD WINAPI 2379 StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) 2380 { 2381 DOC_INFO_1W wDocInfo1 = { 0 }; 2382 DWORD cch; 2383 DWORD dwErrorCode; 2384 DWORD dwReturnValue = 0; 2385 PDOC_INFO_1A pDocInfo1 = (PDOC_INFO_1A)pDocInfo; 2386 2387 TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter, Level, pDocInfo); 2388 2389 // Only check the minimum required for accessing pDocInfo. 2390 // Additional sanity checks are done in StartDocPrinterW. 2391 if (!pDocInfo1) 2392 { 2393 dwErrorCode = ERROR_INVALID_PARAMETER; 2394 goto Cleanup; 2395 } 2396 2397 if (Level != 1) 2398 { 2399 dwErrorCode = ERROR_INVALID_LEVEL; 2400 goto Cleanup; 2401 } 2402 2403 if (pDocInfo1->pDatatype) 2404 { 2405 // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype 2406 cch = strlen(pDocInfo1->pDatatype); 2407 2408 wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2409 if (!wDocInfo1.pDatatype) 2410 { 2411 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2412 ERR("HeapAlloc failed!\n"); 2413 goto Cleanup; 2414 } 2415 2416 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDatatype, -1, wDocInfo1.pDatatype, cch + 1); 2417 } 2418 2419 if (pDocInfo1->pDocName) 2420 { 2421 // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName 2422 cch = strlen(pDocInfo1->pDocName); 2423 2424 wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2425 if (!wDocInfo1.pDocName) 2426 { 2427 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2428 ERR("HeapAlloc failed!\n"); 2429 goto Cleanup; 2430 } 2431 2432 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDocName, -1, wDocInfo1.pDocName, cch + 1); 2433 } 2434 2435 if (pDocInfo1->pOutputFile) 2436 { 2437 // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile 2438 cch = strlen(pDocInfo1->pOutputFile); 2439 2440 wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2441 if (!wDocInfo1.pOutputFile) 2442 { 2443 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2444 ERR("HeapAlloc failed!\n"); 2445 goto Cleanup; 2446 } 2447 2448 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pOutputFile, -1, wDocInfo1.pOutputFile, cch + 1); 2449 } 2450 2451 dwReturnValue = StartDocPrinterW(hPrinter, Level, (PBYTE)&wDocInfo1); 2452 dwErrorCode = GetLastError(); 2453 2454 Cleanup: 2455 if (wDocInfo1.pDatatype) 2456 HeapFree(hProcessHeap, 0, wDocInfo1.pDatatype); 2457 2458 if (wDocInfo1.pDocName) 2459 HeapFree(hProcessHeap, 0, wDocInfo1.pDocName); 2460 2461 if (wDocInfo1.pOutputFile) 2462 HeapFree(hProcessHeap, 0, wDocInfo1.pOutputFile); 2463 2464 SetLastError(dwErrorCode); 2465 return dwReturnValue; 2466 } 2467 2468 DWORD WINAPI 2469 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) 2470 { 2471 DWORD cbAddJobInfo1; 2472 DWORD cbNeeded; 2473 DWORD dwErrorCode; 2474 DWORD dwReturnValue = 0; 2475 PADDJOB_INFO_1W pAddJobInfo1 = NULL; 2476 PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo; 2477 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2478 2479 TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter, Level, pDocInfo); 2480 2481 // Sanity checks. 2482 if (!pHandle) 2483 { 2484 dwErrorCode = ERROR_INVALID_HANDLE; 2485 goto Cleanup; 2486 } 2487 2488 if (!pDocInfo1) 2489 { 2490 dwErrorCode = ERROR_INVALID_PARAMETER; 2491 goto Cleanup; 2492 } 2493 2494 if (Level != 1) 2495 { 2496 dwErrorCode = ERROR_INVALID_LEVEL; 2497 goto Cleanup; 2498 } 2499 2500 if (pHandle->bStartedDoc) 2501 { 2502 dwErrorCode = ERROR_INVALID_PRINTER_STATE; 2503 goto Cleanup; 2504 } 2505 2506 // Check if we want to redirect output into a file. 2507 if (pDocInfo1->pOutputFile) 2508 { 2509 // Do a StartDocPrinter RPC call in this case. 2510 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1); 2511 } 2512 else 2513 { 2514 // Allocate memory for the ADDJOB_INFO_1W structure and a path. 2515 cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR); 2516 pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1); 2517 if (!pAddJobInfo1) 2518 { 2519 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2520 ERR("HeapAlloc failed!\n"); 2521 goto Cleanup; 2522 } 2523 2524 // Try to add a new job. 2525 // This only succeeds if the printer is set to do spooled printing. 2526 if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded)) 2527 { 2528 // Do spooled printing. 2529 dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1); 2530 } 2531 else if (GetLastError() == ERROR_INVALID_ACCESS) 2532 { 2533 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing. 2534 // In this case, we do a StartDocPrinter RPC call. 2535 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1); 2536 } 2537 else 2538 { 2539 dwErrorCode = GetLastError(); 2540 ERR("AddJobW failed with error %lu!\n", dwErrorCode); 2541 goto Cleanup; 2542 } 2543 } 2544 2545 if (dwErrorCode == ERROR_SUCCESS) 2546 { 2547 pHandle->bStartedDoc = TRUE; 2548 dwReturnValue = pHandle->dwJobID; 2549 } 2550 2551 Cleanup: 2552 if (pAddJobInfo1) 2553 HeapFree(hProcessHeap, 0, pAddJobInfo1); 2554 2555 SetLastError(dwErrorCode); 2556 return dwReturnValue; 2557 } 2558 2559 BOOL WINAPI 2560 StartPagePrinter(HANDLE hPrinter) 2561 { 2562 DWORD dwErrorCode; 2563 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2564 2565 TRACE("StartPagePrinter(%p)\n", hPrinter); 2566 2567 // Sanity checks. 2568 if (!pHandle) 2569 { 2570 dwErrorCode = ERROR_INVALID_HANDLE; 2571 goto Cleanup; 2572 } 2573 2574 // Do the RPC call 2575 RpcTryExcept 2576 { 2577 dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter); 2578 } 2579 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2580 { 2581 dwErrorCode = RpcExceptionCode(); 2582 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode); 2583 } 2584 RpcEndExcept; 2585 2586 Cleanup: 2587 SetLastError(dwErrorCode); 2588 return (dwErrorCode == ERROR_SUCCESS); 2589 } 2590 2591 BOOL WINAPI 2592 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten) 2593 { 2594 DWORD dwErrorCode; 2595 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2596 2597 TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pcWritten); 2598 2599 // Sanity checks. 2600 if (!pHandle) 2601 { 2602 dwErrorCode = ERROR_INVALID_HANDLE; 2603 goto Cleanup; 2604 } 2605 2606 if (!pHandle->bStartedDoc) 2607 { 2608 dwErrorCode = ERROR_SPL_NO_STARTDOC; 2609 goto Cleanup; 2610 } 2611 2612 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE) 2613 { 2614 // Write to the spool file. This doesn't need an RPC request. 2615 if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL)) 2616 { 2617 dwErrorCode = GetLastError(); 2618 ERR("WriteFile failed with error %lu!\n", dwErrorCode); 2619 goto Cleanup; 2620 } 2621 2622 dwErrorCode = ERROR_SUCCESS; 2623 } 2624 else 2625 { 2626 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed. 2627 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full. 2628 2629 // Do the RPC call 2630 RpcTryExcept 2631 { 2632 dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten); 2633 } 2634 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2635 { 2636 dwErrorCode = RpcExceptionCode(); 2637 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode); 2638 } 2639 RpcEndExcept; 2640 } 2641 2642 Cleanup: 2643 SetLastError(dwErrorCode); 2644 return (dwErrorCode == ERROR_SUCCESS); 2645 } 2646 2647 BOOL WINAPI 2648 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus) 2649 { 2650 TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus); 2651 return FALSE; 2652 } 2653