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 extern HINSTANCE hinstWinSpool; 14 // 15 // See winddiui.h, ReactOS version is limited. 16 // Loading from XyzUI.dll part of XyzDRV.dll set. example TTYUI.DLL or UniDrvUI.DLL. 17 // 18 typedef DWORD (WINAPI *DEVICECAPABILITIES) (HANDLE,PWSTR,WORD,PVOID,PDEVMODEW); 19 static DEVICECAPABILITIES fpDeviceCapabilities; 20 21 typedef LONG (WINAPI *DEVICEPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM); 22 static DEVICEPROPERTYSHEETS fpDevicePropertySheets; 23 typedef LONG (WINAPI *DOCUMENTPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM); 24 static DOCUMENTPROPERTYSHEETS fpDocumentPropertySheets; 25 26 typedef LONG (WINAPI *COMMONPROPERTYSHEETUIW) (HWND,PFNPROPSHEETUI,LPARAM,LPDWORD); 27 static COMMONPROPERTYSHEETUIW fpCommonPropertySheetUIW; 28 29 typedef LONG (WINAPI *QUERYCOLORPROFILE) (HANDLE,PDEVMODEW,ULONG,PVOID,ULONG*,FLONG*); 30 static QUERYCOLORPROFILE fpQueryColorProfile; 31 32 typedef BOOL (WINAPI *SPOOLERPRINTEREVENT) (LPWSTR,int,DWORD,LPARAM); 33 static SPOOLERPRINTEREVENT fpPrinterEvent; 34 35 typedef BOOL (WINAPI *DEVQUERYPRINT) (HANDLE,LPDEVMODEW,DWORD*); 36 static DEVQUERYPRINT fpDevQueryPrint; 37 38 typedef BOOL (WINAPI *DEVQUERYPRINTEX) (PDEVQUERYPRINT_INFO); 39 static DEVQUERYPRINTEX fpDevQueryPrintEx; 40 41 // 42 // PrintUI.dll 43 // 44 LONG WINAPI ConstructPrinterFriendlyName( PWSTR, PVOID, LPDWORD Size ); 45 typedef LONG (WINAPI *CONSTRUCTPRINTERFRIENDLYNAME) (PWSTR,PVOID,LPDWORD); 46 static CONSTRUCTPRINTERFRIENDLYNAME fpConstructPrinterFriendlyName; 47 48 // 49 // CompstUI User Data 50 // 51 typedef struct _COMPUI_USERDATA 52 { 53 HMODULE hModule; 54 LPWSTR pszPrinterName; 55 } COMPUI_USERDATA, *PCOMPUI_USERDATA; 56 57 // Local Constants 58 59 /** And the award for the most confusingly named setting goes to "Device", for storing the default printer of the current user. 60 Ok, I admit that this has historical reasons. It's still not straightforward in any way though! */ 61 static const WCHAR wszWindowsKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"; 62 static const WCHAR wszDeviceValue[] = L"Device"; 63 64 static DWORD 65 _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB_INFO_1W pAddJobInfo1) 66 { 67 DWORD cbNeeded; 68 DWORD dwErrorCode; 69 PJOB_INFO_1W pJobInfo1 = NULL; 70 71 // Create the spool file. 72 pHandle->hSPLFile = CreateFileW(pAddJobInfo1->Path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); 73 if (pHandle->hSPLFile == INVALID_HANDLE_VALUE) 74 { 75 dwErrorCode = GetLastError(); 76 ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1->Path, dwErrorCode); 77 goto Cleanup; 78 } 79 80 // Get the size of the job information. 81 GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded); 82 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) 83 { 84 dwErrorCode = GetLastError(); 85 ERR("GetJobW failed with error %lu!\n", dwErrorCode); 86 goto Cleanup; 87 } 88 89 // Allocate enough memory for the returned job information. 90 pJobInfo1 = HeapAlloc(hProcessHeap, 0, cbNeeded); 91 if (!pJobInfo1) 92 { 93 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 94 ERR("HeapAlloc failed!\n"); 95 goto Cleanup; 96 } 97 98 // Get the job information. 99 if (!GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, cbNeeded, &cbNeeded)) 100 { 101 dwErrorCode = GetLastError(); 102 ERR("GetJobW failed with error %lu!\n", dwErrorCode); 103 goto Cleanup; 104 } 105 106 // Add our document information. 107 if (pDocInfo1->pDatatype) 108 pJobInfo1->pDatatype = pDocInfo1->pDatatype; 109 110 pJobInfo1->pDocument = pDocInfo1->pDocName; 111 112 // Set the new job information. 113 if (!SetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0)) 114 { 115 dwErrorCode = GetLastError(); 116 ERR("SetJobW failed with error %lu!\n", dwErrorCode); 117 goto Cleanup; 118 } 119 120 // We were successful! 121 pHandle->dwJobID = pAddJobInfo1->JobId; 122 dwErrorCode = ERROR_SUCCESS; 123 124 Cleanup: 125 if (pJobInfo1) 126 HeapFree(hProcessHeap, 0, pJobInfo1); 127 128 return dwErrorCode; 129 } 130 131 static DWORD 132 _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1) 133 { 134 DWORD dwErrorCode; 135 WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer; 136 137 DocInfoContainer.Level = 1; 138 DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1; 139 140 RpcTryExcept 141 { 142 dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer, &pHandle->dwJobID); 143 } 144 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 145 { 146 dwErrorCode = RpcExceptionCode(); 147 ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode); 148 } 149 RpcEndExcept; 150 151 return dwErrorCode; 152 } 153 154 BOOL WINAPI 155 AbortPrinter(HANDLE hPrinter) 156 { 157 DWORD dwErrorCode; 158 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 159 160 TRACE("AbortPrinter(%p)\n", hPrinter); 161 162 // Sanity checks. 163 if (!pHandle) 164 { 165 dwErrorCode = ERROR_INVALID_HANDLE; 166 goto Cleanup; 167 } 168 169 pHandle->bTrayIcon = pHandle->bStartedDoc = FALSE; 170 171 if ( pHandle->hSPLFile != INVALID_HANDLE_VALUE && pHandle->bJob ) 172 { 173 // Close any open file handle. 174 CloseHandle( pHandle->hSPLFile ); 175 pHandle->hSPLFile = INVALID_HANDLE_VALUE; 176 177 SetJobW( hPrinter, pHandle->dwJobID, 0, NULL, JOB_CONTROL_DELETE ); 178 179 return ScheduleJob( hPrinter, pHandle->dwJobID ); 180 } 181 182 // Do the RPC call. 183 RpcTryExcept 184 { 185 dwErrorCode = _RpcAbortPrinter(&pHandle->hPrinter); 186 } 187 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 188 { 189 dwErrorCode = RpcExceptionCode(); 190 ERR("_RpcAbortPrinter failed with exception code %lu!\n", dwErrorCode); 191 } 192 RpcEndExcept; 193 194 Cleanup: 195 SetLastError(dwErrorCode); 196 return (dwErrorCode == ERROR_SUCCESS); 197 } 198 199 HANDLE WINAPI 200 AddPrinterA(PSTR pName, DWORD Level, PBYTE pPrinter) 201 { 202 UNICODE_STRING pNameW, usBuffer; 203 PWSTR pwstrNameW; 204 PRINTER_INFO_2W *ppi2w = (PRINTER_INFO_2W*)pPrinter; 205 PRINTER_INFO_2A *ppi2a = (PRINTER_INFO_2A*)pPrinter; 206 HANDLE ret = NULL; 207 PWSTR pwszPrinterName = NULL; 208 PWSTR pwszServerName = NULL; 209 PWSTR pwszShareName = NULL; 210 PWSTR pwszPortName = NULL; 211 PWSTR pwszDriverName = NULL; 212 PWSTR pwszComment = NULL; 213 PWSTR pwszLocation = NULL; 214 PWSTR pwszSepFile = NULL; 215 PWSTR pwszPrintProcessor = NULL; 216 PWSTR pwszDatatype = NULL; 217 PWSTR pwszParameters = NULL; 218 PDEVMODEW pdmw = NULL; 219 220 TRACE("AddPrinterA(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter); 221 222 if(Level != 2) 223 { 224 ERR("Level = %d, unsupported!\n", Level); 225 SetLastError(ERROR_INVALID_LEVEL); 226 return NULL; 227 } 228 229 pwstrNameW = AsciiToUnicode(&pNameW,pName); 230 231 if (ppi2a->pShareName) 232 { 233 pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName); 234 if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup; 235 } 236 if (ppi2a->pPortName) 237 { 238 pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName); 239 if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup; 240 } 241 if (ppi2a->pDriverName) 242 { 243 pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName); 244 if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup; 245 } 246 if (ppi2a->pComment) 247 { 248 pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment); 249 if (!(ppi2w->pComment = pwszComment)) goto Cleanup; 250 } 251 if (ppi2a->pLocation) 252 { 253 pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation); 254 if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup; 255 } 256 if (ppi2a->pSepFile) 257 { 258 pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile); 259 if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup; 260 } 261 if (ppi2a->pServerName) 262 { 263 pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor); 264 if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup; 265 } 266 if (ppi2a->pDatatype) 267 { 268 pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype); 269 if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup; 270 } 271 if (ppi2a->pParameters) 272 { 273 pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters); 274 if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup; 275 } 276 if ( ppi2a->pDevMode ) 277 { 278 RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw ); 279 ppi2w->pDevMode = pdmw; 280 } 281 if (ppi2a->pServerName) 282 { 283 pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName); 284 if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup; 285 } 286 if (ppi2a->pPrinterName) 287 { 288 pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName); 289 if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup; 290 } 291 292 ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)ppi2w); 293 294 Cleanup: 295 if (pdmw) HeapFree(hProcessHeap, 0, pdmw); 296 if (pwszPrinterName) HeapFree(hProcessHeap, 0, pwszPrinterName); 297 if (pwszServerName) HeapFree(hProcessHeap, 0, pwszServerName); 298 if (pwszShareName) HeapFree(hProcessHeap, 0, pwszShareName); 299 if (pwszPortName) HeapFree(hProcessHeap, 0, pwszPortName); 300 if (pwszDriverName) HeapFree(hProcessHeap, 0, pwszDriverName); 301 if (pwszComment) HeapFree(hProcessHeap, 0, pwszComment); 302 if (pwszLocation) HeapFree(hProcessHeap, 0, pwszLocation); 303 if (pwszSepFile) HeapFree(hProcessHeap, 0, pwszSepFile); 304 if (pwszPrintProcessor) HeapFree(hProcessHeap, 0, pwszPrintProcessor); 305 if (pwszDatatype) HeapFree(hProcessHeap, 0, pwszDatatype); 306 if (pwszParameters) HeapFree(hProcessHeap, 0, pwszParameters); 307 308 RtlFreeUnicodeString(&pNameW); 309 return ret; 310 } 311 312 HANDLE WINAPI 313 AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter) 314 { 315 DWORD dwErrorCode; 316 WINSPOOL_PRINTER_CONTAINER PrinterContainer; 317 WINSPOOL_DEVMODE_CONTAINER DevModeContainer; 318 WINSPOOL_SECURITY_CONTAINER SecurityContainer; 319 SECURITY_DESCRIPTOR *sd = NULL; 320 DWORD size; 321 HANDLE hPrinter = NULL, hHandle = NULL; 322 PSPOOLER_HANDLE pHandle = NULL; 323 324 TRACE("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter); 325 326 DevModeContainer.cbBuf = 0; 327 DevModeContainer.pDevMode = NULL; 328 329 SecurityContainer.cbBuf = 0; 330 SecurityContainer.pSecurity = NULL; 331 332 if ( Level != 2 ) 333 { 334 FIXME( "Unsupported level %d\n", Level ); 335 SetLastError( ERROR_INVALID_LEVEL ); 336 return hHandle; 337 } 338 else 339 { 340 PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter; 341 if ( pi2w ) 342 { 343 if ( pi2w->pDevMode ) 344 { 345 if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) ) 346 { 347 DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra; 348 DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode; 349 } 350 } 351 352 if ( pi2w->pSecurityDescriptor ) 353 { 354 sd = get_sd( pi2w->pSecurityDescriptor, &size ); 355 if ( sd ) 356 { 357 SecurityContainer.cbBuf = size; 358 SecurityContainer.pSecurity = (PBYTE)sd; 359 } 360 } 361 } 362 else 363 { 364 SetLastError(ERROR_INVALID_PARAMETER); 365 return hHandle; 366 } 367 } 368 369 PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter; 370 PrinterContainer.Level = Level; 371 372 // Do the RPC call 373 RpcTryExcept 374 { 375 dwErrorCode = _RpcAddPrinter( pName, &PrinterContainer, &DevModeContainer, &SecurityContainer, &hPrinter ); 376 } 377 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 378 { 379 dwErrorCode = RpcExceptionCode(); 380 } 381 RpcEndExcept; 382 383 if (hPrinter) 384 { 385 // Create a new SPOOLER_HANDLE structure. 386 pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE)); 387 if (!pHandle) 388 { 389 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 390 ERR("HeapAlloc failed!\n"); 391 _RpcDeletePrinter(hPrinter); 392 _RpcClosePrinter(hPrinter); 393 goto Cleanup; 394 } 395 396 pHandle->Sig = SPOOLER_HANDLE_SIG; 397 pHandle->hPrinter = hPrinter; 398 pHandle->hSPLFile = INVALID_HANDLE_VALUE; 399 pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE; 400 hHandle = (HANDLE)pHandle; 401 } 402 403 Cleanup: 404 if ( sd ) HeapFree( GetProcessHeap(), 0, sd ); 405 406 SetLastError(dwErrorCode); 407 return hHandle; 408 } 409 410 BOOL WINAPI 411 ClosePrinter(HANDLE hPrinter) 412 { 413 DWORD dwErrorCode; 414 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 415 416 TRACE("ClosePrinter(%p)\n", hPrinter); 417 418 // Sanity checks. 419 if ( IntProtectHandle( hPrinter, TRUE ) ) 420 { 421 dwErrorCode = ERROR_INVALID_HANDLE; 422 goto Cleanup; 423 } 424 425 // Do the RPC call. 426 RpcTryExcept 427 { 428 dwErrorCode = _RpcClosePrinter(&pHandle->hPrinter); 429 } 430 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 431 { 432 dwErrorCode = RpcExceptionCode(); 433 ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode); 434 } 435 RpcEndExcept; 436 437 // Close any open file handle. 438 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE) 439 CloseHandle(pHandle->hSPLFile); 440 441 pHandle->Sig = -1; 442 443 // Free the memory for the handle. 444 HeapFree(hProcessHeap, 0, pHandle); 445 446 Cleanup: 447 SetLastError(dwErrorCode); 448 return (dwErrorCode == ERROR_SUCCESS); 449 } 450 451 BOOL WINAPI 452 DeletePrinter(HANDLE hPrinter) 453 { 454 DWORD dwErrorCode; 455 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 456 457 TRACE("DeletePrinter(%p)\n", hPrinter); 458 459 // Sanity checks. 460 if (!pHandle) 461 { 462 dwErrorCode = ERROR_INVALID_HANDLE; 463 goto Cleanup; 464 } 465 466 // Do the RPC call. 467 RpcTryExcept 468 { 469 dwErrorCode = _RpcDeletePrinter(&pHandle->hPrinter); 470 } 471 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 472 { 473 dwErrorCode = RpcExceptionCode(); 474 ERR("_RpcDeletePrinter failed with exception code %lu!\n", dwErrorCode); 475 } 476 RpcEndExcept; 477 478 Cleanup: 479 SetLastError(dwErrorCode); 480 return (dwErrorCode == ERROR_SUCCESS); 481 } 482 483 // 484 // Based on GDI32:printdrv.c:IntGetPrinterDriver. 485 // 486 HMODULE 487 WINAPI 488 LoadPrinterDriver( HANDLE hspool ) 489 { 490 INT iTries = 0; 491 DWORD Size = (sizeof(WCHAR) * MAX_PATH) * 2; // DRIVER_INFO_5W + plus strings. 492 PDRIVER_INFO_5W pdi = NULL; 493 HMODULE hLibrary = NULL; 494 495 do 496 { 497 ++iTries; 498 499 pdi = RtlAllocateHeap( GetProcessHeap(), 0, Size); 500 501 if ( !pdi ) 502 break; 503 504 if ( GetPrinterDriverW(hspool, NULL, 5, (LPBYTE)pdi, Size, &Size) ) 505 { 506 TRACE("Level 5 Size %d\n",Size); 507 508 // Name and load configure library (for example, C:\DRIVERS\Pscrptui.dll). Not printui.dll! 509 510 hLibrary = LoadLibrary(pdi->pConfigFile); 511 512 FIXME("IGPD : Get Printer Driver Config File : %S\n",pdi->pConfigFile); 513 514 RtlFreeHeap( GetProcessHeap(), 0, pdi); 515 return hLibrary; 516 } 517 518 if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) 519 ++iTries; 520 521 RtlFreeHeap( GetProcessHeap(), 0, pdi); 522 } 523 while ( iTries < 2 ); 524 ERR("No Printer Driver Error %d\n",GetLastError()); 525 return NULL; 526 } 527 528 DWORD WINAPI 529 DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode) 530 { 531 PWSTR pwszDeviceName = NULL; 532 PDEVMODEW pdmwInput = NULL; 533 BOOL bReturnValue = GDI_ERROR; 534 DWORD cch; 535 536 FIXME("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode); 537 538 if (pDevice) 539 { 540 // Convert pName to a Unicode string pwszDeviceName. 541 cch = strlen(pDevice); 542 543 pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 544 if (!pwszDeviceName) 545 { 546 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 547 ERR("HeapAlloc failed!\n"); 548 goto Cleanup; 549 } 550 551 MultiByteToWideChar(CP_ACP, 0, pDevice, -1, pwszDeviceName, cch + 1); 552 } 553 554 if (pDevMode) 555 { 556 RosConvertAnsiDevModeToUnicodeDevmode((PDEVMODEA)pDevMode, &pdmwInput); 557 } 558 559 // pPort is ignored so no need to pass it. 560 bReturnValue = DeviceCapabilitiesW( pwszDeviceName, NULL, fwCapability, (LPWSTR)pOutput, (const DEVMODEW*) pdmwInput ); 561 562 Cleanup: 563 if(pwszDeviceName) 564 HeapFree(hProcessHeap, 0, pwszDeviceName); 565 566 if (pdmwInput) 567 HeapFree(hProcessHeap, 0, pdmwInput); 568 569 return bReturnValue; 570 } 571 572 DWORD WINAPI 573 DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode) 574 { 575 HANDLE hPrinter; 576 HMODULE hLibrary; 577 DWORD iDevCap = GDI_ERROR; 578 579 FIXME("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode); 580 581 if ( pDevMode ) 582 { 583 if (!IsValidDevmodeNoSizeW( (PDEVMODEW)pDevMode ) ) 584 { 585 ERR("DeviceCapabilitiesW : Devode Invalid\n"); 586 return -1; 587 } 588 } 589 590 if ( OpenPrinterW( (LPWSTR)pDevice, &hPrinter, NULL ) ) 591 { 592 hLibrary = LoadPrinterDriver( hPrinter ); 593 594 if ( hLibrary ) 595 { 596 fpDeviceCapabilities = (PVOID)GetProcAddress( hLibrary, "DrvDeviceCapabilities" ); 597 598 if ( fpDeviceCapabilities ) 599 { 600 iDevCap = fpDeviceCapabilities( hPrinter, (PWSTR)pDevice, fwCapability, pOutput, (PDEVMODE)pDevMode ); 601 } 602 603 FreeLibrary(hLibrary); 604 } 605 606 ClosePrinter( hPrinter ); 607 } 608 609 return iDevCap; 610 } 611 612 BOOL 613 WINAPI 614 DevQueryPrint( HANDLE hPrinter, LPDEVMODEW pDevMode, DWORD *pResID) 615 { 616 HMODULE hLibrary; 617 BOOL Ret = FALSE; 618 619 hLibrary = LoadPrinterDriver( hPrinter ); 620 621 if ( hLibrary ) 622 { 623 fpDevQueryPrint = (PVOID)GetProcAddress( hLibrary, "DevQueryPrint" ); 624 625 if ( fpDevQueryPrint ) 626 { 627 Ret = fpDevQueryPrint( hPrinter, pDevMode, pResID ); 628 } 629 630 FreeLibrary(hLibrary); 631 } 632 return Ret; 633 } 634 635 BOOL WINAPI 636 DevQueryPrintEx( PDEVQUERYPRINT_INFO pDQPInfo ) 637 { 638 HMODULE hLibrary; 639 BOOL Ret = FALSE; 640 641 hLibrary = LoadPrinterDriver( pDQPInfo->hPrinter ); 642 643 if ( hLibrary ) 644 { 645 fpDevQueryPrintEx = (PVOID)GetProcAddress( hLibrary, "DevQueryPrintEx" ); 646 647 if ( fpDevQueryPrintEx ) 648 { 649 Ret = fpDevQueryPrintEx( pDQPInfo ); 650 } 651 652 FreeLibrary(hLibrary); 653 } 654 return Ret; 655 } 656 657 INT WINAPI 658 DocumentEvent( HANDLE hPrinter, HDC hdc, int iEsc, ULONG cbIn, PVOID pvIn, ULONG cbOut, PVOID pvOut) 659 { 660 FIXME("DocumentEvent(%p, %p, %lu, %lu, %p, %lu, %p)\n", hPrinter, hdc, iEsc, cbIn, pvIn, cbOut, pvOut); 661 UNIMPLEMENTED; 662 return DOCUMENTEVENT_UNSUPPORTED; 663 } 664 665 LONG WINAPI 666 DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode) 667 { 668 PWSTR pwszDeviceName = NULL; 669 PDEVMODEW pdmwInput = NULL; 670 PDEVMODEW pdmwOutput = NULL; 671 LONG lReturnValue = -1; 672 DWORD cch; 673 674 FIXME("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode); 675 676 if (pDeviceName) 677 { 678 // Convert pName to a Unicode string pwszDeviceName. 679 cch = strlen(pDeviceName); 680 681 pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 682 if (!pwszDeviceName) 683 { 684 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 685 ERR("HeapAlloc failed!\n"); 686 goto Cleanup; 687 } 688 689 MultiByteToWideChar(CP_ACP, 0, pDeviceName, -1, pwszDeviceName, cch + 1); 690 } 691 692 if (pDevModeInput) 693 { 694 // Create working buffer for input to DocumentPropertiesW. 695 RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput, &pdmwInput); 696 } 697 698 if (pDevModeOutput) 699 { 700 // Create working buffer for output from DocumentPropertiesW. 701 702 // Do it RIGHT! Get the F...ing Size! 703 LONG Size = DocumentPropertiesW( hWnd, hPrinter, pwszDeviceName, NULL, NULL, 0 ); 704 705 if ( Size < 0 ) 706 { 707 goto Cleanup; 708 } 709 710 pdmwOutput = HeapAlloc(hProcessHeap, 0, Size); 711 if (!pdmwOutput) 712 { 713 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 714 ERR("HeapAlloc failed!\n"); 715 goto Cleanup; 716 } 717 } 718 719 lReturnValue = DocumentPropertiesW(hWnd, hPrinter, pwszDeviceName, pdmwOutput, pdmwInput, fMode); 720 FIXME("lReturnValue from DocumentPropertiesW is '%ld'.\n", lReturnValue); 721 722 if (lReturnValue < 0) 723 { 724 FIXME("DocumentPropertiesW failed!\n"); 725 goto Cleanup; 726 } 727 728 if (pdmwOutput) 729 { 730 RosConvertUnicodeDevModeToAnsiDevmode(pdmwOutput, pDevModeOutput); 731 } 732 733 Cleanup: 734 if(pwszDeviceName) 735 HeapFree(hProcessHeap, 0, pwszDeviceName); 736 737 if (pdmwInput) 738 HeapFree(hProcessHeap, 0, pdmwInput); 739 740 if (pdmwOutput) 741 HeapFree(hProcessHeap, 0, pdmwOutput); 742 743 return lReturnValue; 744 } 745 746 PRINTER_INFO_9W * get_devmodeW(HANDLE hprn) 747 { 748 PRINTER_INFO_9W *pi9 = NULL; 749 DWORD needed = 0; 750 BOOL res; 751 752 res = GetPrinterW(hprn, 9, NULL, 0, &needed); 753 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) 754 { 755 pi9 = HeapAlloc(hProcessHeap, 0, needed); 756 if (!pi9) 757 { 758 ERR("Failed to allocate PRINTER_INFO_9W of %u bytes\n", needed); 759 return NULL; 760 } 761 res = GetPrinterW(hprn, 9, (LPBYTE)pi9, needed, &needed); 762 } 763 764 if (res) 765 return pi9; 766 767 ERR("GetPrinterW failed with %u\n", GetLastError()); 768 HeapFree(hProcessHeap, 0, pi9); 769 return NULL; 770 } 771 772 BOOL 773 FASTCALL 774 CreateUIUserData( ULONG_PTR *puserdata, HANDLE hPrinter ) 775 { 776 PCOMPUI_USERDATA pcui_ud = DllAllocSplMem( sizeof(COMPUI_USERDATA) ); 777 778 *puserdata = (ULONG_PTR)pcui_ud; 779 FIXME("CreateUIUserData\n"); 780 if ( pcui_ud ) 781 { 782 pcui_ud->hModule = LoadPrinterDriver( hPrinter ); 783 784 if ( !pcui_ud->hModule ) 785 { 786 DllFreeSplMem( pcui_ud ); 787 *puserdata = 0; 788 } 789 } 790 return *puserdata != 0; 791 } 792 793 VOID 794 FASTCALL 795 DestroyUIUserData( ULONG_PTR *puserdata ) 796 { 797 PCOMPUI_USERDATA pcui_ud = (PCOMPUI_USERDATA)*puserdata; 798 FIXME("DestroyUIUserData\n"); 799 if ( pcui_ud ) 800 { 801 if ( pcui_ud->hModule ) 802 { 803 FreeLibrary( pcui_ud->hModule ); 804 pcui_ud->hModule = NULL; 805 } 806 807 if ( pcui_ud->pszPrinterName ) 808 { 809 DllFreeSplMem( pcui_ud->pszPrinterName ); 810 pcui_ud->pszPrinterName = NULL; 811 } 812 813 DllFreeSplMem( pcui_ud ); 814 *puserdata = 0; 815 } 816 } 817 818 BOOL 819 FASTCALL 820 IntFixUpDevModeNames( PDOCUMENTPROPERTYHEADER pdphdr ) 821 { 822 PRINTER_INFO_2W *pi2 = NULL; 823 DWORD needed = 0; 824 BOOL res; 825 826 if (!(pdphdr->fMode & DM_OUT_BUFFER) || 827 pdphdr->fMode & DM_NOPERMISSION || // Do not allow the user to modify properties on the displayed property sheet pages. 828 !pdphdr->pdmOut ) 829 { 830 return FALSE; 831 } 832 833 res = GetPrinterW( pdphdr->hPrinter, 2, NULL, 0, &needed); 834 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) 835 { 836 pi2 = HeapAlloc(hProcessHeap, 0, needed); 837 if (!pi2) 838 { 839 ERR("Failed to allocate PRINTER_INFO_2W of %u bytes\n", needed); 840 return FALSE; 841 } 842 res = GetPrinterW( pdphdr->hPrinter, 2, (LPBYTE)pi2, needed, &needed); 843 } 844 845 if (res) 846 { 847 /* Check if the provided buffer is large enough */ 848 DWORD cbDevMode = pi2->pDevMode->dmSize + pi2->pDevMode->dmDriverExtra; 849 if (pdphdr->cbOut < cbDevMode) 850 { 851 ERR("cbOut (%lu) < cbDevMode(%u)\n", pdphdr->cbOut, cbDevMode); 852 res = FALSE; 853 goto Exit; 854 } 855 856 /* Copy the devmode */ 857 RtlCopyMemory(pdphdr->pdmOut, pi2->pDevMode, cbDevMode); 858 859 TRACE("IFUDMN : Get Printer Name %S\n", pi2->pPrinterName); 860 StringCchCopyW( pdphdr->pdmOut->dmDeviceName, CCHDEVICENAME-1, pi2->pPrinterName ); 861 pdphdr->pdmOut->dmDeviceName[CCHDEVICENAME-1] = 0; 862 } 863 else 864 { 865 ERR("IFUDMN : GetPrinterW failed with %u\n", GetLastError()); 866 } 867 868 Exit: 869 HeapFree(hProcessHeap, 0, pi2); 870 return res; 871 } 872 873 LONG 874 WINAPI 875 CreatePrinterFriendlyName( PCOMPUI_USERDATA pcui_ud, LPWSTR pszPrinterName ) 876 { 877 LONG Result = 0; 878 DWORD Size = 0; 879 HMODULE hLibrary = NULL; 880 881 hLibrary = LoadLibraryA( "printui.dll" ); 882 883 if ( hLibrary ) 884 { 885 fpConstructPrinterFriendlyName = (PVOID)GetProcAddress( hLibrary, "ConstructPrinterFriendlyName" ); 886 887 if ( fpConstructPrinterFriendlyName ) 888 { 889 if ( !fpConstructPrinterFriendlyName( pszPrinterName, NULL, &Size ) ) 890 { 891 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) 892 { 893 PWSTR pwstr = DllAllocSplMem( (Size + 1) * sizeof(WCHAR) ); 894 895 pcui_ud->pszPrinterName = pwstr; 896 897 if ( pwstr ) 898 Result = fpConstructPrinterFriendlyName( pszPrinterName, pwstr, &Size ); 899 } 900 } 901 } 902 FreeLibrary( hLibrary ); 903 } 904 905 if ( !Result ) 906 { 907 DllFreeSplMem( pcui_ud->pszPrinterName ); 908 pcui_ud->pszPrinterName = AllocSplStr( pszPrinterName ); 909 } 910 911 return Result; 912 } 913 914 // 915 // Tested with XP CompstUI as a callback and works. Fails perfectly. 916 // 917 LONG 918 WINAPI 919 DocumentPropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam ) 920 { 921 LONG Result = -1; 922 PDOCUMENTPROPERTYHEADER pdphdr; 923 924 FIXME("DocumentPropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam); 925 926 // If pPSUIInfo is NULL, and if either lParam -> fMode is zero or lParam -> pdmOut is NULL, 927 // this function should return the size, in bytes, of the printer's DEVMODEW structure. 928 if ( !pCPSUIInfo && lparam ) 929 { 930 pdphdr = (PDOCUMENTPROPERTYHEADER)lparam; 931 932 if ( pdphdr->cbSize >= sizeof(PDOCUMENTPROPERTYHEADER) && 933 !(pdphdr->fMode & DM_PROMPT) ) 934 { 935 HMODULE hLibrary = LoadPrinterDriver( pdphdr->hPrinter ); 936 937 if ( hLibrary ) 938 { 939 fpDocumentPropertySheets = (PVOID)GetProcAddress( hLibrary, "DrvDocumentPropertySheets" ); 940 941 if ( fpDocumentPropertySheets ) 942 { 943 FIXME("DPS : fpDocumentPropertySheets(%p, 0x%lx) pdmOut %p\n", pCPSUIInfo, lparam, pdphdr->pdmOut); 944 Result = fpDocumentPropertySheets( pCPSUIInfo, lparam ); 945 FIXME("DPS : fpDocumentPropertySheets result %d cbOut %d\n",Result, pdphdr->cbOut); 946 } 947 else 948 { 949 // 950 // ReactOS backup!!! Currently no supporting UI driver. 951 // 952 PRINTER_INFO_9W * pi9 = get_devmodeW( pdphdr->hPrinter ); 953 if ( pi9 ) 954 { 955 Result = pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra; 956 FIXME("IDPS : Using ReactOS backup!!! DevMode Size %d\n",Result); 957 HeapFree(hProcessHeap, 0, pi9); 958 } 959 } 960 961 FreeLibrary(hLibrary); 962 963 if ( Result > 0 ) 964 { 965 IntFixUpDevModeNames( pdphdr ); 966 } 967 968 return Result; 969 } 970 else 971 { 972 SetLastError(ERROR_INVALID_HANDLE); 973 } 974 } 975 else 976 { 977 SetLastError(ERROR_INVALID_PARAMETER); 978 } 979 return Result; 980 } 981 982 Result = 0; 983 984 if ( pCPSUIInfo ) 985 { 986 PSETRESULT_INFO psri; 987 PPROPSHEETUI_INFO_HEADER ppsuiihdr; 988 PCOMPUI_USERDATA pcui_ud; 989 pdphdr = (PDOCUMENTPROPERTYHEADER)pCPSUIInfo->lParamInit; 990 991 if ( pdphdr->cbSize < sizeof(PDOCUMENTPROPERTYHEADER) ) 992 { 993 SetLastError(ERROR_INVALID_PARAMETER); 994 return Result; 995 } 996 997 switch ( pCPSUIInfo->Reason ) 998 { 999 case PROPSHEETUI_REASON_INIT: 1000 { 1001 FIXME("DocPS : PROPSHEETUI_REASON_INIT\n"); 1002 if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) ) 1003 { 1004 pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData; 1005 1006 fpDocumentPropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDocumentPropertySheets" ); 1007 1008 if ( fpDocumentPropertySheets ) 1009 { 1010 pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, 1011 CPSFUNC_SET_FUSION_CONTEXT, 1012 -3, // What type of handle is this? 1013 0 ); // Not used, must be zero. 1014 1015 Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, 1016 CPSFUNC_ADD_PFNPROPSHEETUIW, 1017 (LPARAM)fpDocumentPropertySheets, 1018 pCPSUIInfo->lParamInit ); 1019 break; 1020 } 1021 FIXME("DocPS : PROPSHEETUI_REASON_INIT Fail\n"); 1022 DestroyUIUserData( &pCPSUIInfo->UserData ); 1023 } 1024 } 1025 break; 1026 1027 case PROPSHEETUI_REASON_GET_INFO_HEADER: 1028 FIXME("DocPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n"); 1029 1030 ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam; 1031 1032 pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData; 1033 1034 CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName ); 1035 1036 ppsuiihdr->Flags = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE; 1037 ppsuiihdr->pTitle = pcui_ud->pszPrinterName; 1038 ppsuiihdr->hInst = hinstWinSpool; 1039 ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT; 1040 1041 Result = CPSUI_OK; 1042 break; 1043 1044 case PROPSHEETUI_REASON_DESTROY: 1045 FIXME("DocPS : PROPSHEETUI_REASON_DESTROY\n"); 1046 DestroyUIUserData( &pCPSUIInfo->UserData ); 1047 Result = CPSUI_OK; 1048 break; 1049 1050 case PROPSHEETUI_REASON_SET_RESULT: 1051 FIXME("DocPS : PROPSHEETUI_REASON_SET_RESULT\n"); 1052 1053 psri = (PSETRESULT_INFO)lparam; 1054 1055 pCPSUIInfo->Result = psri->Result; 1056 if ( pCPSUIInfo->Result > 0 ) 1057 { 1058 IntFixUpDevModeNames( pdphdr ); 1059 } 1060 Result = CPSUI_OK; 1061 break; 1062 } 1063 } 1064 return Result; 1065 } 1066 1067 LONG 1068 WINAPI 1069 DevicePropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam ) 1070 { 1071 LONG Result = 0; 1072 PDEVICEPROPERTYHEADER pdphdr; 1073 1074 FIXME("DevicePropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam); 1075 1076 if ( pCPSUIInfo ) 1077 { 1078 PSETRESULT_INFO psri; 1079 PPROPSHEETUI_INFO_HEADER ppsuiihdr; 1080 PCOMPUI_USERDATA pcui_ud; 1081 pdphdr = (PDEVICEPROPERTYHEADER)pCPSUIInfo->lParamInit; 1082 1083 if ( pdphdr->cbSize < sizeof(DEVICEPROPERTYHEADER) ) 1084 { 1085 SetLastError(ERROR_INVALID_PARAMETER); 1086 return Result; 1087 } 1088 1089 switch ( pCPSUIInfo->Reason ) 1090 { 1091 case PROPSHEETUI_REASON_INIT: 1092 { 1093 FIXME("DevPS : PROPSHEETUI_REASON_INIT\n"); 1094 if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) ) 1095 { 1096 pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData; 1097 1098 fpDevicePropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDevicePropertySheets" ); 1099 1100 if ( fpDevicePropertySheets ) 1101 { 1102 pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, 1103 CPSFUNC_SET_FUSION_CONTEXT, 1104 -3, // What type of handle is this? 1105 0 ); // Not used, must be zero. 1106 1107 Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet, 1108 CPSFUNC_ADD_PFNPROPSHEETUIW, 1109 (LPARAM)fpDevicePropertySheets, 1110 pCPSUIInfo->lParamInit ); 1111 break; 1112 } 1113 FIXME("DevPS : PROPSHEETUI_REASON_INIT Fail\n"); 1114 DestroyUIUserData( &pCPSUIInfo->UserData ); 1115 } 1116 } 1117 break; 1118 1119 case PROPSHEETUI_REASON_GET_INFO_HEADER: 1120 FIXME("DevPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n"); 1121 1122 ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam; 1123 1124 pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData; 1125 1126 CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName ); 1127 1128 ppsuiihdr->Flags = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE; 1129 ppsuiihdr->pTitle = pcui_ud->pszPrinterName; 1130 ppsuiihdr->hInst = hinstWinSpool; 1131 ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT; 1132 1133 Result = CPSUI_OK; 1134 break; 1135 1136 case PROPSHEETUI_REASON_DESTROY: 1137 FIXME("DevPS : PROPSHEETUI_REASON_DESTROY\n"); 1138 DestroyUIUserData( &pCPSUIInfo->UserData ); 1139 Result = CPSUI_OK; 1140 break; 1141 1142 case PROPSHEETUI_REASON_SET_RESULT: 1143 FIXME("DevPS : PROPSHEETUI_REASON_SET_RESULT\n"); 1144 psri = (PSETRESULT_INFO)lparam; 1145 pCPSUIInfo->Result = psri->Result; 1146 Result = CPSUI_OK; 1147 break; 1148 } 1149 } 1150 return Result; 1151 } 1152 1153 LONG 1154 WINAPI 1155 CallCommonPropertySheetUI(HWND hWnd, PFNPROPSHEETUI pfnPropSheetUI, LPARAM lparam, LPDWORD pResult) 1156 { 1157 HMODULE hLibrary = NULL; 1158 LONG Ret = ERR_CPSUI_GETLASTERROR; 1159 1160 FIXME("CallCommonPropertySheetUI(%p, %p, 0x%lx, %p)\n", hWnd, pfnPropSheetUI, lparam, pResult); 1161 1162 if ( ( hLibrary = LoadLibraryA( "compstui.dll" ) ) ) 1163 { 1164 fpCommonPropertySheetUIW = (PVOID) GetProcAddress(hLibrary, "CommonPropertySheetUIW"); 1165 1166 if ( fpCommonPropertySheetUIW ) 1167 { 1168 Ret = fpCommonPropertySheetUIW( hWnd, pfnPropSheetUI, lparam, pResult ); 1169 } 1170 1171 FreeLibrary(hLibrary); 1172 } 1173 return Ret; 1174 } 1175 1176 LONG WINAPI 1177 DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode) 1178 { 1179 HANDLE hUseHandle = NULL; 1180 DOCUMENTPROPERTYHEADER docprophdr; 1181 LONG Result = IDOK; 1182 1183 FIXME("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode); 1184 1185 if (hPrinter) 1186 { 1187 hUseHandle = hPrinter; 1188 } 1189 else if (!OpenPrinterW(pDeviceName, &hUseHandle, NULL)) 1190 { 1191 ERR("No handle, and no usable printer name passed in\n"); 1192 return -1; 1193 } 1194 1195 if ( !(fMode & DM_IN_BUFFER ) || 1196 ( ( pDevModeInput && !IsValidDevmodeNoSizeW( (PDEVMODEW)pDevModeInput ) ) ) ) 1197 { 1198 pDevModeInput = NULL; 1199 fMode &= ~DM_IN_BUFFER; 1200 } 1201 1202 docprophdr.cbSize = sizeof(DOCUMENTPROPERTYHEADER); 1203 docprophdr.Reserved = 0; 1204 docprophdr.hPrinter = hUseHandle; 1205 docprophdr.pszPrinterName = pDeviceName; 1206 docprophdr.cbOut = 0; 1207 1208 if ( pDevModeOutput ) 1209 { 1210 docprophdr.pdmIn = NULL; 1211 docprophdr.pdmOut = NULL; 1212 docprophdr.fMode = 0; 1213 FIXME("DPW : Call DocumentPropertySheets with pDevModeOutput %p\n",pDevModeOutput); 1214 docprophdr.cbOut = DocumentPropertySheets( NULL, (LPARAM)&docprophdr ); 1215 } 1216 1217 docprophdr.pdmIn = pDevModeInput; 1218 docprophdr.pdmOut = pDevModeOutput; 1219 docprophdr.fMode = fMode; 1220 1221 if ( fMode & DM_IN_PROMPT ) 1222 { 1223 Result = CPSUI_CANCEL; 1224 1225 // 1226 // Now call the Property Sheet for Print > Properties. 1227 // 1228 if ( CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DocumentPropertySheets, (LPARAM)&docprophdr, (LPDWORD)&Result ) < 0 ) 1229 { 1230 FIXME("CallCommonPropertySheetUI return error\n"); 1231 Result = ERR_CPSUI_GETLASTERROR; 1232 } 1233 else 1234 Result = (Result == CPSUI_OK) ? IDOK : IDCANCEL; 1235 FIXME("CallCommonPropertySheetUI returned\n"); 1236 } 1237 else 1238 { 1239 FIXME("DPW : CallDocumentPropertySheets\n"); 1240 Result = DocumentPropertySheets( NULL, (LPARAM)&docprophdr ); 1241 } 1242 1243 if ( Result != ERR_CPSUI_GETLASTERROR || Result != ERR_CPSUI_ALLOCMEM_FAILED ) 1244 { 1245 if ( pDevModeOutput ) 1246 { 1247 if ( !IsValidDevmodeNoSizeW( pDevModeOutput ) ) 1248 { 1249 ERR("DPW : Improper pDevModeOutput size.\n"); 1250 Result = -1; 1251 } 1252 } 1253 else 1254 { 1255 ERR("No pDevModeOutput\n"); 1256 } 1257 } 1258 1259 if (hUseHandle && !hPrinter) 1260 ClosePrinter(hUseHandle); 1261 return Result; 1262 } 1263 1264 BOOL 1265 WINAPI 1266 PrinterProperties( HWND hWnd, HANDLE hPrinter ) 1267 { 1268 PRINTER_INFO_2W *pi2 = NULL; 1269 DWORD needed = 0; 1270 LONG Ret, Result = 0; 1271 BOOL res; 1272 DEVICEPROPERTYHEADER devprophdr; 1273 1274 FIXME("PrinterProperties(%p, %p)\n", hWnd, hPrinter); 1275 1276 devprophdr.cbSize = sizeof(DEVICEPROPERTYHEADER); 1277 devprophdr.Flags = DPS_NOPERMISSION; 1278 devprophdr.hPrinter = hPrinter; 1279 devprophdr.pszPrinterName = NULL; 1280 1281 res = GetPrinterW( hPrinter, 2, NULL, 0, &needed); 1282 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) 1283 { 1284 pi2 = HeapAlloc(hProcessHeap, 0, needed); 1285 if (!pi2) 1286 { 1287 ERR("Failed to allocate PRINTER_INFO_2W of %u bytes\n", needed); 1288 return FALSE; 1289 } 1290 res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed); 1291 } 1292 1293 // 1294 // Above can fail, still process w/o printer name. 1295 // 1296 if ( res ) devprophdr.pszPrinterName = pi2->pPrinterName; 1297 1298 needed = 1; 1299 1300 if ( ( SetPrinterDataW( hPrinter, L"PrinterPropertiesPermission", REG_DWORD, (LPBYTE)&needed, sizeof(DWORD) ) == ERROR_SUCCESS ) ) 1301 { 1302 devprophdr.Flags &= ~DPS_NOPERMISSION; 1303 } 1304 1305 Ret = CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DevicePropertySheets, (LPARAM)&devprophdr, (LPDWORD)&Result ); 1306 1307 res = (Ret >= 0); 1308 1309 if (!res) 1310 { 1311 FIXME("PrinterProperties fail ICPSUI\n"); 1312 } 1313 1314 if (pi2) HeapFree(hProcessHeap, 0, pi2); 1315 1316 return res; 1317 } 1318 1319 BOOL WINAPI 1320 EndDocPrinter(HANDLE hPrinter) 1321 { 1322 DWORD dwErrorCode; 1323 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 1324 1325 TRACE("EndDocPrinter(%p)\n", hPrinter); 1326 1327 // Sanity checks. 1328 if (!pHandle) 1329 { 1330 dwErrorCode = ERROR_INVALID_HANDLE; 1331 goto Cleanup; 1332 } 1333 1334 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE) 1335 { 1336 // For spooled jobs, the document is finished by calling _RpcScheduleJob. 1337 RpcTryExcept 1338 { 1339 dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID); 1340 } 1341 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 1342 { 1343 dwErrorCode = RpcExceptionCode(); 1344 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode); 1345 } 1346 RpcEndExcept; 1347 1348 // Close the spool file handle. 1349 CloseHandle(pHandle->hSPLFile); 1350 } 1351 else 1352 { 1353 // In all other cases, just call _RpcEndDocPrinter. 1354 RpcTryExcept 1355 { 1356 dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter); 1357 } 1358 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 1359 { 1360 dwErrorCode = RpcExceptionCode(); 1361 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode); 1362 } 1363 RpcEndExcept; 1364 } 1365 1366 // A new document can now be started again. 1367 pHandle->bTrayIcon = pHandle->bJob = pHandle->bStartedDoc = FALSE; 1368 1369 Cleanup: 1370 SetLastError(dwErrorCode); 1371 return (dwErrorCode == ERROR_SUCCESS); 1372 } 1373 1374 BOOL WINAPI 1375 EndPagePrinter(HANDLE hPrinter) 1376 { 1377 DWORD dwErrorCode; 1378 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 1379 1380 TRACE("EndPagePrinter(%p)\n", hPrinter); 1381 1382 // Sanity checks. 1383 if (!pHandle) 1384 { 1385 dwErrorCode = ERROR_INVALID_HANDLE; 1386 goto Cleanup; 1387 } 1388 1389 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE) 1390 { 1391 // For spooled jobs, we don't need to do anything. 1392 dwErrorCode = ERROR_SUCCESS; 1393 } 1394 else 1395 { 1396 // In all other cases, just call _RpcEndPagePrinter. 1397 RpcTryExcept 1398 { 1399 dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter); 1400 } 1401 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 1402 { 1403 dwErrorCode = RpcExceptionCode(); 1404 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode); 1405 } 1406 RpcEndExcept; 1407 } 1408 1409 Cleanup: 1410 SetLastError(dwErrorCode); 1411 return (dwErrorCode == ERROR_SUCCESS); 1412 } 1413 1414 BOOL WINAPI 1415 EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 1416 { 1417 DWORD dwErrorCode; 1418 DWORD cch; 1419 PWSTR pwszName = NULL; 1420 PSTR pszPrinterName = NULL; 1421 PSTR pszServerName = NULL; 1422 PSTR pszDescription = NULL; 1423 PSTR pszName = NULL; 1424 PSTR pszComment = NULL; 1425 PSTR pszShareName = NULL; 1426 PSTR pszPortName = NULL; 1427 PSTR pszDriverName = NULL; 1428 PSTR pszLocation = NULL; 1429 PSTR pszSepFile = NULL; 1430 PSTR pszPrintProcessor = NULL; 1431 PSTR pszDatatype = NULL; 1432 PSTR pszParameters = NULL; 1433 DWORD i; 1434 PPRINTER_INFO_1W ppi1w = NULL; 1435 PPRINTER_INFO_1A ppi1a = NULL; 1436 PPRINTER_INFO_2W ppi2w = NULL; 1437 PPRINTER_INFO_2A ppi2a = NULL; 1438 PPRINTER_INFO_4W ppi4w = NULL; 1439 PPRINTER_INFO_4A ppi4a = NULL; 1440 PPRINTER_INFO_5W ppi5w = NULL; 1441 PPRINTER_INFO_5A ppi5a = NULL; 1442 1443 TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); 1444 1445 // Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable. 1446 if (Level != 1 && Level != 2 && Level != 4 && Level != 5) 1447 { 1448 dwErrorCode = ERROR_INVALID_LEVEL; 1449 ERR("Invalid Level!\n"); 1450 goto Cleanup; 1451 } 1452 1453 if (Name) 1454 { 1455 // Convert pName to a Unicode string pwszName. 1456 cch = strlen(Name); 1457 1458 pwszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 1459 if (!pwszName) 1460 { 1461 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1462 ERR("HeapAlloc failed!\n"); 1463 goto Cleanup; 1464 } 1465 1466 MultiByteToWideChar(CP_ACP, 0, Name, -1, pwszName, cch + 1); 1467 } 1468 1469 /* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */ 1470 if (!EnumPrintersW(Flags, pwszName, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned)) 1471 { 1472 dwErrorCode = GetLastError(); 1473 goto Cleanup; 1474 } 1475 1476 /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */ 1477 /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */ 1478 /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */ 1479 1480 /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */ 1481 ppi1w = (PPRINTER_INFO_1W)pPrinterEnum; 1482 ppi2w = (PPRINTER_INFO_2W)pPrinterEnum; 1483 ppi4w = (PPRINTER_INFO_4W)pPrinterEnum; 1484 ppi5w = (PPRINTER_INFO_5W)pPrinterEnum; 1485 /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */ 1486 ppi1a = (PPRINTER_INFO_1A)pPrinterEnum; 1487 ppi2a = (PPRINTER_INFO_2A)pPrinterEnum; 1488 ppi4a = (PPRINTER_INFO_4A)pPrinterEnum; 1489 ppi5a = (PPRINTER_INFO_5A)pPrinterEnum; 1490 1491 for (i = 0; i < *pcReturned; i++) 1492 { 1493 switch (Level) 1494 { 1495 case 1: 1496 { 1497 if (ppi1w[i].pDescription) 1498 { 1499 // Convert Unicode pDescription to a ANSI string pszDescription. 1500 cch = wcslen(ppi1w[i].pDescription); 1501 1502 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1503 if (!pszDescription) 1504 { 1505 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1506 ERR("HeapAlloc failed!\n"); 1507 goto Cleanup; 1508 } 1509 1510 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pDescription, -1, pszDescription, cch + 1, NULL, NULL); 1511 StringCchCopyA(ppi1a[i].pDescription, cch + 1, pszDescription); 1512 1513 HeapFree(hProcessHeap, 0, pszDescription); 1514 } 1515 1516 if (ppi1w[i].pName) 1517 { 1518 // Convert Unicode pName to a ANSI string pszName. 1519 cch = wcslen(ppi1w[i].pName); 1520 1521 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1522 if (!pszName) 1523 { 1524 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1525 ERR("HeapAlloc failed!\n"); 1526 goto Cleanup; 1527 } 1528 1529 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pName, -1, pszName, cch + 1, NULL, NULL); 1530 StringCchCopyA(ppi1a[i].pName, cch + 1, pszName); 1531 1532 HeapFree(hProcessHeap, 0, pszName); 1533 } 1534 1535 if (ppi1w[i].pComment) 1536 { 1537 // Convert Unicode pComment to a ANSI string pszComment. 1538 cch = wcslen(ppi1w[i].pComment); 1539 1540 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1541 if (!pszComment) 1542 { 1543 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1544 ERR("HeapAlloc failed!\n"); 1545 goto Cleanup; 1546 } 1547 1548 WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pComment, -1, pszComment, cch + 1, NULL, NULL); 1549 StringCchCopyA(ppi1a[i].pComment, cch + 1, pszComment); 1550 1551 HeapFree(hProcessHeap, 0, pszComment); 1552 } 1553 break; 1554 } 1555 1556 1557 case 2: 1558 { 1559 if (ppi2w[i].pServerName) 1560 { 1561 // Convert Unicode pServerName to a ANSI string pszServerName. 1562 cch = wcslen(ppi2w[i].pServerName); 1563 1564 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1565 if (!pszServerName) 1566 { 1567 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1568 ERR("HeapAlloc failed!\n"); 1569 goto Cleanup; 1570 } 1571 1572 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL); 1573 StringCchCopyA(ppi2a[i].pServerName, cch + 1, pszServerName); 1574 1575 HeapFree(hProcessHeap, 0, pszServerName); 1576 } 1577 1578 if (ppi2w[i].pPrinterName) 1579 { 1580 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 1581 cch = wcslen(ppi2w[i].pPrinterName); 1582 1583 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1584 if (!pszPrinterName) 1585 { 1586 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1587 ERR("HeapAlloc failed!\n"); 1588 goto Cleanup; 1589 } 1590 1591 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 1592 StringCchCopyA(ppi2a[i].pPrinterName, cch + 1, pszPrinterName); 1593 1594 HeapFree(hProcessHeap, 0, pszPrinterName); 1595 } 1596 1597 if (ppi2w[i].pShareName) 1598 { 1599 // Convert Unicode pShareName to a ANSI string pszShareName. 1600 cch = wcslen(ppi2w[i].pShareName); 1601 1602 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1603 if (!pszShareName) 1604 { 1605 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1606 ERR("HeapAlloc failed!\n"); 1607 goto Cleanup; 1608 } 1609 1610 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pShareName, -1, pszShareName, cch + 1, NULL, NULL); 1611 StringCchCopyA(ppi2a[i].pShareName, cch + 1, pszShareName); 1612 1613 HeapFree(hProcessHeap, 0, pszShareName); 1614 } 1615 1616 if (ppi2w[i].pPortName) 1617 { 1618 // Convert Unicode pPortName to a ANSI string pszPortName. 1619 cch = wcslen(ppi2w[i].pPortName); 1620 1621 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1622 if (!pszPortName) 1623 { 1624 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1625 ERR("HeapAlloc failed!\n"); 1626 goto Cleanup; 1627 } 1628 1629 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL); 1630 StringCchCopyA(ppi2a[i].pPortName, cch + 1, pszPortName); 1631 1632 HeapFree(hProcessHeap, 0, pszPortName); 1633 } 1634 1635 if (ppi2w[i].pDriverName) 1636 { 1637 // Convert Unicode pDriverName to a ANSI string pszDriverName. 1638 cch = wcslen(ppi2w[i].pDriverName); 1639 1640 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1641 if (!pszDriverName) 1642 { 1643 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1644 ERR("HeapAlloc failed!\n"); 1645 goto Cleanup; 1646 } 1647 1648 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDriverName, -1, pszDriverName, cch + 1, NULL, NULL); 1649 StringCchCopyA(ppi2a[i].pDriverName, cch + 1, pszDriverName); 1650 1651 HeapFree(hProcessHeap, 0, pszDriverName); 1652 } 1653 1654 if (ppi2w[i].pComment) 1655 { 1656 // Convert Unicode pComment to a ANSI string pszComment. 1657 cch = wcslen(ppi2w[i].pComment); 1658 1659 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1660 if (!pszComment) 1661 { 1662 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1663 ERR("HeapAlloc failed!\n"); 1664 goto Cleanup; 1665 } 1666 1667 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pComment, -1, pszComment, cch + 1, NULL, NULL); 1668 StringCchCopyA(ppi2a[i].pComment, cch + 1, pszComment); 1669 1670 HeapFree(hProcessHeap, 0, pszComment); 1671 } 1672 1673 if (ppi2w[i].pLocation) 1674 { 1675 // Convert Unicode pLocation to a ANSI string pszLocation. 1676 cch = wcslen(ppi2w[i].pLocation); 1677 1678 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1679 if (!pszLocation) 1680 { 1681 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1682 ERR("HeapAlloc failed!\n"); 1683 goto Cleanup; 1684 } 1685 1686 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pLocation, -1, pszLocation, cch + 1, NULL, NULL); 1687 StringCchCopyA(ppi2a[i].pLocation, cch + 1, pszLocation); 1688 1689 HeapFree(hProcessHeap, 0, pszLocation); 1690 } 1691 1692 1693 if (ppi2w[i].pSepFile) 1694 { 1695 // Convert Unicode pSepFile to a ANSI string pszSepFile. 1696 cch = wcslen(ppi2w[i].pSepFile); 1697 1698 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1699 if (!pszSepFile) 1700 { 1701 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1702 ERR("HeapAlloc failed!\n"); 1703 goto Cleanup; 1704 } 1705 1706 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pSepFile, -1, pszSepFile, cch + 1, NULL, NULL); 1707 StringCchCopyA(ppi2a[i].pSepFile, cch + 1, pszSepFile); 1708 1709 HeapFree(hProcessHeap, 0, pszSepFile); 1710 } 1711 1712 if (ppi2w[i].pPrintProcessor) 1713 { 1714 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor. 1715 cch = wcslen(ppi2w[i].pPrintProcessor); 1716 1717 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1718 if (!pszPrintProcessor) 1719 { 1720 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1721 ERR("HeapAlloc failed!\n"); 1722 goto Cleanup; 1723 } 1724 1725 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL); 1726 StringCchCopyA(ppi2a[i].pPrintProcessor, cch + 1, pszPrintProcessor); 1727 1728 HeapFree(hProcessHeap, 0, pszPrintProcessor); 1729 } 1730 1731 1732 if (ppi2w[i].pDatatype) 1733 { 1734 // Convert Unicode pDatatype to a ANSI string pszDatatype. 1735 cch = wcslen(ppi2w[i].pDatatype); 1736 1737 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1738 if (!pszDatatype) 1739 { 1740 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1741 ERR("HeapAlloc failed!\n"); 1742 goto Cleanup; 1743 } 1744 1745 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDatatype, -1, pszDatatype, cch + 1, NULL, NULL); 1746 StringCchCopyA(ppi2a[i].pDatatype, cch + 1, pszDatatype); 1747 1748 HeapFree(hProcessHeap, 0, pszDatatype); 1749 } 1750 1751 if (ppi2w[i].pParameters) 1752 { 1753 // Convert Unicode pParameters to a ANSI string pszParameters. 1754 cch = wcslen(ppi2w[i].pParameters); 1755 1756 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1757 if (!pszParameters) 1758 { 1759 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1760 ERR("HeapAlloc failed!\n"); 1761 goto Cleanup; 1762 } 1763 1764 WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pParameters, -1, pszParameters, cch + 1, NULL, NULL); 1765 StringCchCopyA(ppi2a[i].pParameters, cch + 1, pszParameters); 1766 1767 HeapFree(hProcessHeap, 0, pszParameters); 1768 } 1769 if ( ppi2w[i].pDevMode ) 1770 { 1771 RosConvertUnicodeDevModeToAnsiDevmode( ppi2w[i].pDevMode, ppi2a[i].pDevMode ); 1772 } 1773 break; 1774 } 1775 1776 case 4: 1777 { 1778 if (ppi4w[i].pPrinterName) 1779 { 1780 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 1781 cch = wcslen(ppi4w[i].pPrinterName); 1782 1783 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1784 if (!pszPrinterName) 1785 { 1786 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1787 ERR("HeapAlloc failed!\n"); 1788 goto Cleanup; 1789 } 1790 1791 WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 1792 StringCchCopyA(ppi4a[i].pPrinterName, cch + 1, pszPrinterName); 1793 1794 HeapFree(hProcessHeap, 0, pszPrinterName); 1795 } 1796 1797 if (ppi4w[i].pServerName) 1798 { 1799 // Convert Unicode pServerName to a ANSI string pszServerName. 1800 cch = wcslen(ppi4w[i].pServerName); 1801 1802 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1803 if (!pszServerName) 1804 { 1805 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1806 ERR("HeapAlloc failed!\n"); 1807 goto Cleanup; 1808 } 1809 1810 WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL); 1811 StringCchCopyA(ppi4a[i].pServerName, cch + 1, pszServerName); 1812 1813 HeapFree(hProcessHeap, 0, pszServerName); 1814 } 1815 break; 1816 } 1817 1818 case 5: 1819 { 1820 if (ppi5w[i].pPrinterName) 1821 { 1822 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 1823 cch = wcslen(ppi5w[i].pPrinterName); 1824 1825 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1826 if (!pszPrinterName) 1827 { 1828 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1829 ERR("HeapAlloc failed!\n"); 1830 goto Cleanup; 1831 } 1832 1833 WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 1834 StringCchCopyA(ppi5a[i].pPrinterName, cch + 1, pszPrinterName); 1835 1836 HeapFree(hProcessHeap, 0, pszPrinterName); 1837 } 1838 1839 if (ppi5w[i].pPortName) 1840 { 1841 // Convert Unicode pPortName to a ANSI string pszPortName. 1842 cch = wcslen(ppi5w[i].pPortName); 1843 1844 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 1845 if (!pszPortName) 1846 { 1847 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1848 ERR("HeapAlloc failed!\n"); 1849 goto Cleanup; 1850 } 1851 1852 WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL); 1853 StringCchCopyA(ppi5a[i].pPortName, cch + 1, pszPortName); 1854 1855 HeapFree(hProcessHeap, 0, pszPortName); 1856 } 1857 break; 1858 } 1859 1860 } // switch 1861 } // for 1862 1863 dwErrorCode = ERROR_SUCCESS; 1864 1865 Cleanup: 1866 if (pwszName) 1867 { 1868 HeapFree(hProcessHeap, 0, pwszName); 1869 } 1870 1871 SetLastError(dwErrorCode); 1872 return (dwErrorCode == ERROR_SUCCESS); 1873 } 1874 1875 BOOL WINAPI 1876 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 1877 { 1878 DWORD dwErrorCode; 1879 1880 TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); 1881 1882 // Dismiss invalid levels already at this point. 1883 if (Level == 3 || Level > 5) 1884 { 1885 dwErrorCode = ERROR_INVALID_LEVEL; 1886 goto Cleanup; 1887 } 1888 1889 if (cbBuf && pPrinterEnum) 1890 ZeroMemory(pPrinterEnum, cbBuf); 1891 1892 // Do the RPC call 1893 RpcTryExcept 1894 { 1895 dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); 1896 } 1897 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 1898 { 1899 dwErrorCode = RpcExceptionCode(); 1900 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode); 1901 } 1902 RpcEndExcept; 1903 1904 if (dwErrorCode == ERROR_SUCCESS) 1905 { 1906 // Replace relative offset addresses in the output by absolute pointers. 1907 ASSERT(Level <= 9); 1908 MarshallUpStructuresArray(cbBuf, pPrinterEnum, *pcReturned, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE); 1909 } 1910 1911 Cleanup: 1912 SetLastError(dwErrorCode); 1913 return (dwErrorCode == ERROR_SUCCESS); 1914 } 1915 1916 BOOL WINAPI 1917 FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep) 1918 { 1919 TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter, pBuf, cbBuf, pcWritten, cSleep); 1920 UNIMPLEMENTED; 1921 return FALSE; 1922 } 1923 1924 BOOL WINAPI 1925 GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer) 1926 { 1927 DWORD dwErrorCode; 1928 PWSTR pwszBuffer = NULL; 1929 1930 TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer, pcchBuffer); 1931 1932 // Sanity check. 1933 if (!pcchBuffer) 1934 { 1935 dwErrorCode = ERROR_INVALID_PARAMETER; 1936 goto Cleanup; 1937 } 1938 1939 // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size. 1940 if (pszBuffer && *pcchBuffer) 1941 { 1942 pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR)); 1943 if (!pwszBuffer) 1944 { 1945 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1946 ERR("HeapAlloc failed!\n"); 1947 goto Cleanup; 1948 } 1949 } 1950 1951 if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer)) 1952 { 1953 dwErrorCode = GetLastError(); 1954 goto Cleanup; 1955 } 1956 1957 // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI. 1958 WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, *pcchBuffer, NULL, NULL); 1959 1960 dwErrorCode = ERROR_SUCCESS; 1961 1962 Cleanup: 1963 if (pwszBuffer) 1964 HeapFree(hProcessHeap, 0, pwszBuffer); 1965 1966 SetLastError(dwErrorCode); 1967 return (dwErrorCode == ERROR_SUCCESS); 1968 } 1969 1970 BOOL WINAPI 1971 GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer) 1972 { 1973 DWORD cbNeeded; 1974 DWORD cchInputBuffer; 1975 DWORD dwErrorCode; 1976 HKEY hWindowsKey = NULL; 1977 PWSTR pwszDevice = NULL; 1978 PWSTR pwszComma; 1979 1980 TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer, pcchBuffer); 1981 1982 // Sanity check. 1983 if (!pcchBuffer) 1984 { 1985 dwErrorCode = ERROR_INVALID_PARAMETER; 1986 goto Cleanup; 1987 } 1988 1989 cchInputBuffer = *pcchBuffer; 1990 1991 // Open the registry key where the default printer for the current user is stored. 1992 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey); 1993 if (dwErrorCode != ERROR_SUCCESS) 1994 { 1995 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); 1996 goto Cleanup; 1997 } 1998 1999 // Determine the size of the required buffer. 2000 dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded); 2001 if (dwErrorCode != ERROR_SUCCESS) 2002 { 2003 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); 2004 goto Cleanup; 2005 } 2006 2007 // Allocate it. 2008 pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded); 2009 if (!pwszDevice) 2010 { 2011 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2012 ERR("HeapAlloc failed!\n"); 2013 goto Cleanup; 2014 } 2015 2016 // Now get the actual value. 2017 dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded); 2018 if (dwErrorCode != ERROR_SUCCESS) 2019 { 2020 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); 2021 goto Cleanup; 2022 } 2023 2024 // We get a string "<Printer Name>,winspool,<Port>:". 2025 // Extract the printer name from it. 2026 pwszComma = wcschr(pwszDevice, L','); 2027 if (!pwszComma) 2028 { 2029 ERR("Found no or invalid default printer: %S!\n", pwszDevice); 2030 dwErrorCode = ERROR_INVALID_NAME; 2031 goto Cleanup; 2032 } 2033 2034 // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer. 2035 *pcchBuffer = pwszComma - pwszDevice + 1; 2036 2037 // Check if the supplied buffer is large enough. 2038 if ( !pszBuffer || cchInputBuffer < *pcchBuffer) 2039 { 2040 dwErrorCode = ERROR_INSUFFICIENT_BUFFER; 2041 goto Cleanup; 2042 } 2043 2044 // Copy the default printer. 2045 *pwszComma = 0; 2046 CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR)); 2047 2048 dwErrorCode = ERROR_SUCCESS; 2049 2050 Cleanup: 2051 if (hWindowsKey) 2052 RegCloseKey(hWindowsKey); 2053 2054 if (pwszDevice) 2055 HeapFree(hProcessHeap, 0, pwszDevice); 2056 2057 SetLastError(dwErrorCode); 2058 return (dwErrorCode == ERROR_SUCCESS); 2059 } 2060 2061 BOOL WINAPI 2062 GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) 2063 { 2064 DWORD dwErrorCode; 2065 PPRINTER_INFO_1A ppi1a = (PPRINTER_INFO_1A)pPrinter; 2066 PPRINTER_INFO_1W ppi1w = (PPRINTER_INFO_1W)pPrinter; 2067 PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter; 2068 PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter; 2069 PPRINTER_INFO_4A ppi4a = (PPRINTER_INFO_4A)pPrinter; 2070 PPRINTER_INFO_4W ppi4w = (PPRINTER_INFO_4W)pPrinter; 2071 PPRINTER_INFO_5A ppi5a = (PPRINTER_INFO_5A)pPrinter; 2072 PPRINTER_INFO_5W ppi5w = (PPRINTER_INFO_5W)pPrinter; 2073 PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter; 2074 PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter; 2075 PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter; 2076 PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter; 2077 DWORD cch; 2078 2079 TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 2080 2081 // Check for invalid levels here for early error return. Should be 1-9. 2082 if (Level < 1 || Level > 9) 2083 { 2084 dwErrorCode = ERROR_INVALID_LEVEL; 2085 ERR("Invalid Level!\n"); 2086 goto Cleanup; 2087 } 2088 2089 if (!GetPrinterW(hPrinter, Level, pPrinter, cbBuf, pcbNeeded)) 2090 { 2091 dwErrorCode = GetLastError(); 2092 goto Cleanup; 2093 } 2094 2095 switch (Level) 2096 { 2097 case 1: 2098 { 2099 if (ppi1w->pDescription) 2100 { 2101 PSTR pszDescription; 2102 2103 // Convert Unicode pDescription to a ANSI string pszDescription. 2104 cch = wcslen(ppi1w->pDescription); 2105 2106 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2107 if (!pszDescription) 2108 { 2109 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2110 ERR("HeapAlloc failed!\n"); 2111 goto Cleanup; 2112 } 2113 2114 WideCharToMultiByte(CP_ACP, 0, ppi1w->pDescription, -1, pszDescription, cch + 1, NULL, NULL); 2115 StringCchCopyA(ppi1a->pDescription, cch + 1, pszDescription); 2116 2117 HeapFree(hProcessHeap, 0, pszDescription); 2118 } 2119 2120 if (ppi1w->pName) 2121 { 2122 PSTR pszName; 2123 2124 // Convert Unicode pName to a ANSI string pszName. 2125 cch = wcslen(ppi1w->pName); 2126 2127 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2128 if (!pszName) 2129 { 2130 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2131 ERR("HeapAlloc failed!\n"); 2132 goto Cleanup; 2133 } 2134 2135 WideCharToMultiByte(CP_ACP, 0, ppi1w->pName, -1, pszName, cch + 1, NULL, NULL); 2136 StringCchCopyA(ppi1a->pName, cch + 1, pszName); 2137 2138 HeapFree(hProcessHeap, 0, pszName); 2139 } 2140 2141 if (ppi1w->pComment) 2142 { 2143 PSTR pszComment; 2144 2145 // Convert Unicode pComment to a ANSI string pszComment. 2146 cch = wcslen(ppi1w->pComment); 2147 2148 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2149 if (!pszComment) 2150 { 2151 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2152 ERR("HeapAlloc failed!\n"); 2153 goto Cleanup; 2154 } 2155 2156 WideCharToMultiByte(CP_ACP, 0, ppi1w->pComment, -1, pszComment, cch + 1, NULL, NULL); 2157 StringCchCopyA(ppi1a->pComment, cch + 1, pszComment); 2158 2159 HeapFree(hProcessHeap, 0, pszComment); 2160 } 2161 break; 2162 } 2163 2164 case 2: 2165 { 2166 if (ppi2w->pServerName) 2167 { 2168 PSTR pszServerName; 2169 2170 // Convert Unicode pServerName to a ANSI string pszServerName. 2171 cch = wcslen(ppi2w->pServerName); 2172 2173 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2174 if (!pszServerName) 2175 { 2176 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2177 ERR("HeapAlloc failed!\n"); 2178 goto Cleanup; 2179 } 2180 2181 WideCharToMultiByte(CP_ACP, 0, ppi2w->pServerName, -1, pszServerName, cch + 1, NULL, NULL); 2182 StringCchCopyA(ppi2a->pServerName, cch + 1, pszServerName); 2183 2184 HeapFree(hProcessHeap, 0, pszServerName); 2185 } 2186 2187 if (ppi2w->pPrinterName) 2188 { 2189 PSTR pszPrinterName; 2190 2191 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 2192 cch = wcslen(ppi2w->pPrinterName); 2193 2194 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2195 if (!pszPrinterName) 2196 { 2197 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2198 ERR("HeapAlloc failed!\n"); 2199 goto Cleanup; 2200 } 2201 2202 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 2203 StringCchCopyA(ppi2a->pPrinterName, cch + 1, pszPrinterName); 2204 2205 HeapFree(hProcessHeap, 0, pszPrinterName); 2206 } 2207 2208 if (ppi2w->pShareName) 2209 { 2210 PSTR pszShareName; 2211 2212 // Convert Unicode pShareName to a ANSI string pszShareName. 2213 cch = wcslen(ppi2w->pShareName); 2214 2215 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2216 if (!pszShareName) 2217 { 2218 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2219 ERR("HeapAlloc failed!\n"); 2220 goto Cleanup; 2221 } 2222 2223 WideCharToMultiByte(CP_ACP, 0, ppi2w->pShareName, -1, pszShareName, cch + 1, NULL, NULL); 2224 StringCchCopyA(ppi2a->pShareName, cch + 1, pszShareName); 2225 2226 HeapFree(hProcessHeap, 0, pszShareName); 2227 } 2228 2229 if (ppi2w->pPortName) 2230 { 2231 PSTR pszPortName; 2232 2233 // Convert Unicode pPortName to a ANSI string pszPortName. 2234 cch = wcslen(ppi2w->pPortName); 2235 2236 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2237 if (!pszPortName) 2238 { 2239 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2240 ERR("HeapAlloc failed!\n"); 2241 goto Cleanup; 2242 } 2243 2244 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPortName, -1, pszPortName, cch + 1, NULL, NULL); 2245 StringCchCopyA(ppi2a->pPortName, cch + 1, pszPortName); 2246 2247 HeapFree(hProcessHeap, 0, pszPortName); 2248 } 2249 2250 if (ppi2w->pDriverName) 2251 { 2252 PSTR pszDriverName; 2253 2254 // Convert Unicode pDriverName to a ANSI string pszDriverName. 2255 cch = wcslen(ppi2w->pDriverName); 2256 2257 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2258 if (!pszDriverName) 2259 { 2260 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2261 ERR("HeapAlloc failed!\n"); 2262 goto Cleanup; 2263 } 2264 2265 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDriverName, -1, pszDriverName, cch + 1, NULL, NULL); 2266 StringCchCopyA(ppi2a->pDriverName, cch + 1, pszDriverName); 2267 2268 HeapFree(hProcessHeap, 0, pszDriverName); 2269 } 2270 2271 if (ppi2w->pComment) 2272 { 2273 PSTR pszComment; 2274 2275 // Convert Unicode pComment to a ANSI string pszComment. 2276 cch = wcslen(ppi2w->pComment); 2277 2278 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2279 if (!pszComment) 2280 { 2281 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2282 ERR("HeapAlloc failed!\n"); 2283 goto Cleanup; 2284 } 2285 2286 WideCharToMultiByte(CP_ACP, 0, ppi2w->pComment, -1, pszComment, cch + 1, NULL, NULL); 2287 StringCchCopyA(ppi2a->pComment, cch + 1, pszComment); 2288 2289 HeapFree(hProcessHeap, 0, pszComment); 2290 } 2291 2292 if (ppi2w->pLocation) 2293 { 2294 PSTR pszLocation; 2295 2296 // Convert Unicode pLocation to a ANSI string pszLocation. 2297 cch = wcslen(ppi2w->pLocation); 2298 2299 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2300 if (!pszLocation) 2301 { 2302 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2303 ERR("HeapAlloc failed!\n"); 2304 goto Cleanup; 2305 } 2306 2307 WideCharToMultiByte(CP_ACP, 0, ppi2w->pLocation, -1, pszLocation, cch + 1, NULL, NULL); 2308 StringCchCopyA(ppi2a->pLocation, cch + 1, pszLocation); 2309 2310 HeapFree(hProcessHeap, 0, pszLocation); 2311 } 2312 2313 if (ppi2w->pSepFile) 2314 { 2315 PSTR pszSepFile; 2316 2317 // Convert Unicode pSepFile to a ANSI string pszSepFile. 2318 cch = wcslen(ppi2w->pSepFile); 2319 2320 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2321 if (!pszSepFile) 2322 { 2323 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2324 ERR("HeapAlloc failed!\n"); 2325 goto Cleanup; 2326 } 2327 2328 WideCharToMultiByte(CP_ACP, 0, ppi2w->pSepFile, -1, pszSepFile, cch + 1, NULL, NULL); 2329 StringCchCopyA(ppi2a->pSepFile, cch + 1, pszSepFile); 2330 2331 HeapFree(hProcessHeap, 0, pszSepFile); 2332 } 2333 2334 if (ppi2w->pPrintProcessor) 2335 { 2336 PSTR pszPrintProcessor; 2337 2338 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor. 2339 cch = wcslen(ppi2w->pPrintProcessor); 2340 2341 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2342 if (!pszPrintProcessor) 2343 { 2344 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2345 ERR("HeapAlloc failed!\n"); 2346 goto Cleanup; 2347 } 2348 2349 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL); 2350 StringCchCopyA(ppi2a->pPrintProcessor, cch + 1, pszPrintProcessor); 2351 2352 HeapFree(hProcessHeap, 0, pszPrintProcessor); 2353 } 2354 2355 if (ppi2w->pDatatype) 2356 { 2357 PSTR pszDatatype; 2358 2359 // Convert Unicode pDatatype to a ANSI string pszDatatype. 2360 cch = wcslen(ppi2w->pDatatype); 2361 2362 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2363 if (!pszDatatype) 2364 { 2365 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2366 ERR("HeapAlloc failed!\n"); 2367 goto Cleanup; 2368 } 2369 2370 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDatatype, -1, pszDatatype, cch + 1, NULL, NULL); 2371 StringCchCopyA(ppi2a->pDatatype, cch + 1, pszDatatype); 2372 2373 HeapFree(hProcessHeap, 0, pszDatatype); 2374 } 2375 2376 if (ppi2w->pParameters) 2377 { 2378 PSTR pszParameters; 2379 2380 // Convert Unicode pParameters to a ANSI string pszParameters. 2381 cch = wcslen(ppi2w->pParameters); 2382 2383 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2384 if (!pszParameters) 2385 { 2386 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2387 ERR("HeapAlloc failed!\n"); 2388 goto Cleanup; 2389 } 2390 2391 WideCharToMultiByte(CP_ACP, 0, ppi2w->pParameters, -1, pszParameters, cch + 1, NULL, NULL); 2392 StringCchCopyA(ppi2a->pParameters, cch + 1, pszParameters); 2393 2394 HeapFree(hProcessHeap, 0, pszParameters); 2395 } 2396 if ( ppi2w->pDevMode ) 2397 { 2398 RosConvertUnicodeDevModeToAnsiDevmode( ppi2w->pDevMode, ppi2a->pDevMode ); 2399 } 2400 break; 2401 } 2402 2403 case 4: 2404 { 2405 if (ppi4w->pPrinterName) 2406 { 2407 PSTR pszPrinterName; 2408 2409 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 2410 cch = wcslen(ppi4w->pPrinterName); 2411 2412 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2413 if (!pszPrinterName) 2414 { 2415 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2416 ERR("HeapAlloc failed!\n"); 2417 goto Cleanup; 2418 } 2419 2420 WideCharToMultiByte(CP_ACP, 0, ppi4w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 2421 StringCchCopyA(ppi4a->pPrinterName, cch + 1, pszPrinterName); 2422 2423 HeapFree(hProcessHeap, 0, pszPrinterName); 2424 } 2425 2426 if (ppi4w->pServerName) 2427 { 2428 PSTR pszServerName; 2429 2430 // Convert Unicode pServerName to a ANSI string pszServerName. 2431 cch = wcslen(ppi4w->pServerName); 2432 2433 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2434 if (!pszServerName) 2435 { 2436 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2437 ERR("HeapAlloc failed!\n"); 2438 goto Cleanup; 2439 } 2440 2441 WideCharToMultiByte(CP_ACP, 0, ppi4w->pServerName, -1, pszServerName, cch + 1, NULL, NULL); 2442 StringCchCopyA(ppi4a->pServerName, cch + 1, pszServerName); 2443 2444 HeapFree(hProcessHeap, 0, pszServerName); 2445 } 2446 break; 2447 } 2448 2449 case 5: 2450 { 2451 if (ppi5w->pPrinterName) 2452 { 2453 PSTR pszPrinterName; 2454 2455 // Convert Unicode pPrinterName to a ANSI string pszPrinterName. 2456 cch = wcslen(ppi5w->pPrinterName); 2457 2458 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2459 if (!pszPrinterName) 2460 { 2461 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2462 ERR("HeapAlloc failed!\n"); 2463 goto Cleanup; 2464 } 2465 2466 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL); 2467 StringCchCopyA(ppi5a->pPrinterName, cch + 1, pszPrinterName); 2468 2469 HeapFree(hProcessHeap, 0, pszPrinterName); 2470 } 2471 2472 if (ppi5w->pPortName) 2473 { 2474 PSTR pszPortName; 2475 2476 // Convert Unicode pPortName to a ANSI string pszPortName. 2477 cch = wcslen(ppi5w->pPortName); 2478 2479 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2480 if (!pszPortName) 2481 { 2482 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2483 ERR("HeapAlloc failed!\n"); 2484 goto Cleanup; 2485 } 2486 2487 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPortName, -1, pszPortName, cch + 1, NULL, NULL); 2488 StringCchCopyA(ppi5a->pPortName, cch + 1, pszPortName); 2489 2490 HeapFree(hProcessHeap, 0, pszPortName); 2491 } 2492 break; 2493 } 2494 2495 case 7: 2496 { 2497 if (ppi7w->pszObjectGUID) 2498 { 2499 PSTR pszaObjectGUID; 2500 2501 // Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID. 2502 cch = wcslen(ppi7w->pszObjectGUID); 2503 2504 pszaObjectGUID = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR)); 2505 if (!pszaObjectGUID) 2506 { 2507 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2508 ERR("HeapAlloc failed!\n"); 2509 goto Cleanup; 2510 } 2511 2512 WideCharToMultiByte(CP_ACP, 0, ppi7w->pszObjectGUID, -1, pszaObjectGUID, cch + 1, NULL, NULL); 2513 StringCchCopyA(ppi7a->pszObjectGUID, cch + 1, pszaObjectGUID); 2514 2515 HeapFree(hProcessHeap, 0, pszaObjectGUID); 2516 } 2517 } 2518 break; 2519 case 8: 2520 case 9: 2521 RosConvertUnicodeDevModeToAnsiDevmode(ppi9w->pDevMode, ppi9a->pDevMode); 2522 break; 2523 } // switch 2524 2525 dwErrorCode = ERROR_SUCCESS; 2526 2527 Cleanup: 2528 SetLastError(dwErrorCode); 2529 return (dwErrorCode == ERROR_SUCCESS); 2530 } 2531 2532 BOOL WINAPI 2533 GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) 2534 { 2535 DWORD dwErrorCode; 2536 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2537 2538 TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 2539 2540 // Sanity checks. 2541 if (!pHandle) 2542 { 2543 dwErrorCode = ERROR_INVALID_HANDLE; 2544 goto Cleanup; 2545 } 2546 2547 // Dismiss invalid levels already at this point. 2548 if (Level > 9) 2549 { 2550 dwErrorCode = ERROR_INVALID_LEVEL; 2551 goto Cleanup; 2552 } 2553 2554 if (cbBuf && pPrinter) 2555 ZeroMemory(pPrinter, cbBuf); 2556 2557 // Do the RPC call 2558 RpcTryExcept 2559 { 2560 dwErrorCode = _RpcGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 2561 } 2562 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2563 { 2564 dwErrorCode = RpcExceptionCode(); 2565 ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode); 2566 } 2567 RpcEndExcept; 2568 2569 if (dwErrorCode == ERROR_SUCCESS) 2570 { 2571 // Replace relative offset addresses in the output by absolute pointers. 2572 ASSERT(Level <= 9); 2573 MarshallUpStructure(cbBuf, pPrinter, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE); 2574 } 2575 2576 Cleanup: 2577 SetLastError(dwErrorCode); 2578 return (dwErrorCode == ERROR_SUCCESS); 2579 } 2580 2581 BOOL WINAPI 2582 OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault) 2583 { 2584 BOOL bReturnValue = FALSE; 2585 DWORD cch; 2586 PWSTR pwszPrinterName = NULL; 2587 PRINTER_DEFAULTSW wDefault = { 0 }; 2588 2589 TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName, phPrinter, pDefault); 2590 2591 if (pPrinterName) 2592 { 2593 // Convert pPrinterName to a Unicode string pwszPrinterName 2594 cch = strlen(pPrinterName); 2595 2596 pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2597 if (!pwszPrinterName) 2598 { 2599 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2600 ERR("HeapAlloc failed!\n"); 2601 goto Cleanup; 2602 } 2603 2604 MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, cch + 1); 2605 } 2606 2607 if (pDefault) 2608 { 2609 wDefault.DesiredAccess = pDefault->DesiredAccess; 2610 2611 if (pDefault->pDatatype) 2612 { 2613 // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype 2614 cch = strlen(pDefault->pDatatype); 2615 2616 wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 2617 if (!wDefault.pDatatype) 2618 { 2619 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 2620 ERR("HeapAlloc failed!\n"); 2621 goto Cleanup; 2622 } 2623 2624 MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, wDefault.pDatatype, cch + 1); 2625 } 2626 2627 if (pDefault->pDevMode) 2628 wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode); 2629 } 2630 2631 bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault); 2632 2633 if ( bReturnValue ) 2634 { 2635 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)*phPrinter; 2636 pHandle->bAnsi = TRUE; 2637 } 2638 2639 Cleanup: 2640 if (wDefault.pDatatype) 2641 HeapFree(hProcessHeap, 0, wDefault.pDatatype); 2642 2643 if (wDefault.pDevMode) 2644 HeapFree(hProcessHeap, 0, wDefault.pDevMode); 2645 2646 if (pwszPrinterName) 2647 HeapFree(hProcessHeap, 0, pwszPrinterName); 2648 2649 return bReturnValue; 2650 } 2651 2652 BOOL WINAPI 2653 OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault) 2654 { 2655 DWORD dwErrorCode; 2656 HANDLE hPrinter; 2657 PSPOOLER_HANDLE pHandle; 2658 PWSTR pDatatype = NULL; 2659 WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 }; 2660 ACCESS_MASK AccessRequired = 0; 2661 2662 TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName, phPrinter, pDefault); 2663 2664 // Sanity check 2665 if (!phPrinter) 2666 { 2667 dwErrorCode = ERROR_INVALID_PARAMETER; 2668 goto Cleanup; 2669 } 2670 2671 // Prepare the additional parameters in the format required by _RpcOpenPrinter 2672 if (pDefault) 2673 { 2674 pDatatype = pDefault->pDatatype; 2675 DevModeContainer.cbBuf = sizeof(DEVMODEW); 2676 DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode; 2677 AccessRequired = pDefault->DesiredAccess; 2678 } 2679 2680 // Do the RPC call 2681 RpcTryExcept 2682 { 2683 dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired); 2684 } 2685 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2686 { 2687 dwErrorCode = RpcExceptionCode(); 2688 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode); 2689 } 2690 RpcEndExcept; 2691 2692 if (dwErrorCode == ERROR_SUCCESS) 2693 { 2694 // Create a new SPOOLER_HANDLE structure. 2695 pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE)); 2696 if (!pHandle) 2697 { 2698 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 2699 ERR("HeapAlloc failed!\n"); 2700 goto Cleanup; 2701 } 2702 2703 pHandle->Sig = SPOOLER_HANDLE_SIG; 2704 pHandle->hPrinter = hPrinter; 2705 pHandle->hSPLFile = INVALID_HANDLE_VALUE; 2706 pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE; 2707 2708 // Return it as phPrinter. 2709 *phPrinter = (HANDLE)pHandle; 2710 } 2711 2712 Cleanup: 2713 SetLastError(dwErrorCode); 2714 return (dwErrorCode == ERROR_SUCCESS); 2715 } 2716 2717 // 2718 // Dead API. 2719 // 2720 DWORD WINAPI 2721 PrinterMessageBoxA(HANDLE hPrinter, DWORD Error, HWND hWnd, LPSTR pText, LPSTR pCaption, DWORD dwType) 2722 { 2723 return 50; 2724 } 2725 2726 DWORD WINAPI 2727 PrinterMessageBoxW(HANDLE hPrinter, DWORD Error, HWND hWnd, LPWSTR pText, LPWSTR pCaption, DWORD dwType) 2728 { 2729 return 50; 2730 } 2731 2732 BOOL WINAPI 2733 QueryColorProfile( 2734 HANDLE hPrinter, 2735 PDEVMODEW pdevmode, 2736 ULONG ulQueryMode, 2737 VOID *pvProfileData, 2738 ULONG *pcbProfileData, 2739 FLONG *pflProfileData ) 2740 { 2741 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2742 BOOL Ret = FALSE; 2743 HMODULE hLibrary; 2744 2745 FIXME("QueryColorProfile(%p, %p, %l, %p, %p, %p)\n", hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData); 2746 2747 if ( pHandle->bNoColorProfile ) 2748 { 2749 Ret = (BOOL)SP_ERROR; 2750 } 2751 else 2752 { 2753 2754 if ( pdevmode ) 2755 { 2756 if (!IsValidDevmodeNoSizeW( pdevmode ) ) 2757 { 2758 ERR("QueryColorProfile : Devode Invalid\n"); 2759 return FALSE; 2760 } 2761 } 2762 2763 hLibrary = LoadPrinterDriver( hPrinter ); 2764 2765 if ( hLibrary ) 2766 { 2767 fpQueryColorProfile = (PVOID)GetProcAddress( hLibrary, "DrvQueryColorProfile" ); 2768 2769 if ( fpQueryColorProfile ) 2770 { 2771 Ret = fpQueryColorProfile( hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData ); 2772 } 2773 else 2774 { 2775 pHandle->bNoColorProfile = TRUE; 2776 Ret = (BOOL)SP_ERROR; 2777 } 2778 2779 FreeLibrary(hLibrary); 2780 } 2781 } 2782 return Ret; 2783 } 2784 2785 // Note from GDI32:printdrv.c 2786 // 2787 // QuerySpoolMode : 2788 // BOOL return TRUE if successful. 2789 // dlFont 0x0001 for Downloading fonts. 0x0002 unknown XPS_PASS?. 2790 // dwVersion is version of EMFSPOOL. Must be 0x00010000. See [MS-EMFSPOOL] page 18. 2791 // 2792 2793 #define QSM_DOWNLOADINGFONTS 0x0001 2794 2795 /* 2796 Note from MSDN : "V4 print drivers using RAW mode to send PCL/Postscript have 0 byte spool file" 2797 2798 Use XPS_PASS instead of RAW to pass information directly to the print filter pipeline in 2799 v4 and v3 XPSDrv drivers. Here's how to proceed with Windows 8: 2800 2801 Call GetPrinterDriver to retrieve the DRIVER_INFO_8 structure. 2802 Check DRIVER_INFO_8::dwPrinterDriverAttributes for the PRINTER_DRIVER_XPS flag. 2803 Choose your datatype based on the presence or absence of the flag: 2804 If the flag is set, use XPS_PASS. 2805 If the flag isn't set, use RAW. 2806 */ 2807 2808 #define QSM_XPS_PASS 0x0002 // Guessing. PRINTER_DRIVER_XPS? 2809 2810 BOOL WINAPI 2811 QuerySpoolMode( HANDLE hPrinter, PDWORD downloadFontsFlags, PDWORD dwVersion ) 2812 { 2813 PRINTER_INFO_2W *pi2 = NULL; 2814 DWORD needed = 0; 2815 BOOL res; 2816 2817 FIXME("QuerySpoolMode(%p, %p, %p)\n", hPrinter, downloadFontsFlags, dwVersion); 2818 2819 res = GetPrinterW( hPrinter, 2, NULL, 0, &needed); 2820 if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) 2821 { 2822 pi2 = HeapAlloc(hProcessHeap, 0, needed); 2823 if (!pi2) 2824 { 2825 ERR("Failed to allocate PRINTER_INFO_2W of %u bytes\n", needed); 2826 return FALSE; 2827 } 2828 res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed); 2829 } 2830 2831 if ( res ) 2832 { 2833 *dwVersion = 0x10000; 2834 *downloadFontsFlags = 0; 2835 2836 if ( pi2->pServerName ) 2837 { 2838 *downloadFontsFlags |= QSM_DOWNLOADINGFONTS; 2839 } 2840 } 2841 // 2842 // Guessing,,, 2843 // To do : Add GetPrinterDriver for DRIVER_INFO_8, test PRINTER_DRIVER_XPS flag, 2844 // to set *downloadFontsFlags |= QSM_XPS_PASS; 2845 // 2846 // Vista+ looks for QSM_XPS_PASS to be set in GDI32. 2847 // 2848 HeapFree(hProcessHeap, 0, pi2); 2849 return res; 2850 } 2851 2852 // 2853 // This requires IC support. 2854 // 2855 DWORD WINAPI 2856 QueryRemoteFonts( HANDLE hPrinter, PUNIVERSAL_FONT_ID pufi, ULONG NumberOfUFIs ) 2857 { 2858 HANDLE hIC; 2859 DWORD Result = -1, cOut, cIn = 0; 2860 PBYTE pOut; 2861 2862 FIXME("QueryRemoteFonts(%p, %p, %lu)\n", hPrinter, pufi, NumberOfUFIs); 2863 2864 hIC = CreatePrinterIC( hPrinter, NULL ); 2865 if ( hIC ) 2866 { 2867 cOut = (NumberOfUFIs * sizeof(UNIVERSAL_FONT_ID)) + sizeof(DWORD); // Include "DWORD" first part to return size. 2868 2869 pOut = HeapAlloc( hProcessHeap, 0, cOut ); 2870 if ( pOut ) 2871 { 2872 if ( PlayGdiScriptOnPrinterIC( hIC, (LPBYTE)&cIn, sizeof(DWORD), pOut, cOut, 0 ) ) 2873 { 2874 cIn = *((PDWORD)pOut); // Fisrt part is the size of the UFID object. 2875 2876 Result = cIn; // Return the required size. 2877 2878 if( NumberOfUFIs < cIn ) 2879 { 2880 cIn = NumberOfUFIs; 2881 } 2882 // Copy whole object back to GDI32, exclude first DWORD part. 2883 memcpy( pufi, pOut + sizeof(DWORD), cIn * sizeof(UNIVERSAL_FONT_ID) ); 2884 } 2885 HeapFree( hProcessHeap, 0, pOut ); 2886 } 2887 DeletePrinterIC( hIC ); 2888 } 2889 return Result; 2890 } 2891 2892 BOOL WINAPI 2893 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead) 2894 { 2895 DWORD dwErrorCode; 2896 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2897 2898 TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pNoBytesRead); 2899 2900 // Sanity checks. 2901 if (!pHandle) 2902 { 2903 dwErrorCode = ERROR_INVALID_HANDLE; 2904 goto Cleanup; 2905 } 2906 2907 // Do the RPC call 2908 RpcTryExcept 2909 { 2910 dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead); 2911 } 2912 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2913 { 2914 dwErrorCode = RpcExceptionCode(); 2915 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode); 2916 } 2917 RpcEndExcept; 2918 2919 Cleanup: 2920 SetLastError(dwErrorCode); 2921 return (dwErrorCode == ERROR_SUCCESS); 2922 } 2923 2924 BOOL WINAPI 2925 ResetPrinterA(HANDLE hPrinter, PPRINTER_DEFAULTSA pDefault) 2926 { 2927 BOOL ret; 2928 UNICODE_STRING pNameW; 2929 PDEVMODEW pdmw = NULL; 2930 PPRINTER_DEFAULTSW pdw = (PPRINTER_DEFAULTSW)pDefault; 2931 2932 TRACE("ResetPrinterA(%p, %p)\n", hPrinter, pDefault); 2933 2934 if ( pDefault->pDatatype == (LPSTR)-1 ) 2935 { 2936 pdw->pDatatype = (LPWSTR)-1; 2937 } 2938 else 2939 { 2940 pdw->pDatatype = AsciiToUnicode( &pNameW, pDefault->pDatatype ); 2941 } 2942 if ( pDefault->pDevMode == (LPDEVMODEA)-1) 2943 { 2944 pdw->pDevMode = (LPDEVMODEW)-1; 2945 } 2946 else 2947 { 2948 if ( pDefault->pDevMode )//&& IsValidDevmodeNoSizeW( pDefault->pDevMode ) ) 2949 { 2950 RosConvertAnsiDevModeToUnicodeDevmode( pDefault->pDevMode, &pdmw ); 2951 pdw->pDevMode = pdmw; 2952 } 2953 } 2954 2955 ret = ResetPrinterW( hPrinter, pdw ); 2956 2957 if (pdmw) HeapFree(hProcessHeap, 0, pdmw); 2958 2959 RtlFreeUnicodeString( &pNameW ); 2960 2961 return ret; 2962 } 2963 2964 BOOL WINAPI 2965 ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault) 2966 { 2967 TRACE("ResetPrinterW(%p, %p)\n", hPrinter, pDefault); 2968 UNIMPLEMENTED; 2969 return FALSE; 2970 } 2971 2972 BOOL WINAPI 2973 SeekPrinter( HANDLE hPrinter, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER pliNewPointer, DWORD dwMoveMethod, BOOL bWrite ) 2974 { 2975 DWORD dwErrorCode; 2976 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 2977 2978 FIXME("SeekPrinter(%p, %I64u, %p, %lu, %d)\n", hPrinter, liDistanceToMove.QuadPart, pliNewPointer, dwMoveMethod, bWrite); 2979 2980 // Sanity checks. 2981 if (!pHandle) 2982 { 2983 dwErrorCode = ERROR_INVALID_HANDLE; 2984 goto Cleanup; 2985 } 2986 2987 // Do the RPC call 2988 RpcTryExcept 2989 { 2990 dwErrorCode = _RpcSeekPrinter(pHandle->hPrinter, liDistanceToMove, pliNewPointer, dwMoveMethod, bWrite); 2991 } 2992 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 2993 { 2994 dwErrorCode = RpcExceptionCode(); 2995 ERR("_RpcSeekPrinter failed with exception code %lu!\n", dwErrorCode); 2996 } 2997 RpcEndExcept; 2998 2999 Cleanup: 3000 SetLastError(dwErrorCode); 3001 return (dwErrorCode == ERROR_SUCCESS); 3002 } 3003 3004 BOOL WINAPI 3005 SetDefaultPrinterA(LPCSTR pszPrinter) 3006 { 3007 BOOL bReturnValue = FALSE; 3008 DWORD cch; 3009 PWSTR pwszPrinter = NULL; 3010 3011 TRACE("SetDefaultPrinterA(%s)\n", pszPrinter); 3012 3013 if (pszPrinter) 3014 { 3015 // Convert pszPrinter to a Unicode string pwszPrinter 3016 cch = strlen(pszPrinter); 3017 3018 pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 3019 if (!pwszPrinter) 3020 { 3021 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3022 ERR("HeapAlloc failed!\n"); 3023 goto Cleanup; 3024 } 3025 3026 MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, pwszPrinter, cch + 1); 3027 } 3028 3029 bReturnValue = SetDefaultPrinterW(pwszPrinter); 3030 3031 Cleanup: 3032 if (pwszPrinter) 3033 HeapFree(hProcessHeap, 0, pwszPrinter); 3034 3035 return bReturnValue; 3036 } 3037 3038 BOOL WINAPI 3039 SetDefaultPrinterW(LPCWSTR pszPrinter) 3040 { 3041 const WCHAR wszDevicesKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices"; 3042 3043 DWORD cbDeviceValueData; 3044 DWORD cbPrinterValueData = 0; 3045 DWORD cchPrinter; 3046 DWORD dwErrorCode; 3047 HKEY hDevicesKey = NULL; 3048 HKEY hWindowsKey = NULL; 3049 PWSTR pwszDeviceValueData = NULL; 3050 WCHAR wszPrinter[MAX_PRINTER_NAME + 1]; 3051 3052 TRACE("SetDefaultPrinterW(%S)\n", pszPrinter); 3053 3054 // Open the Devices registry key. 3055 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszDevicesKey, 0, KEY_READ, &hDevicesKey); 3056 if (dwErrorCode != ERROR_SUCCESS) 3057 { 3058 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); 3059 goto Cleanup; 3060 } 3061 3062 // Did the caller give us a printer to set as default? 3063 if (pszPrinter && *pszPrinter) 3064 { 3065 // Check if the given printer exists and query the value data size. 3066 dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, NULL, &cbPrinterValueData); 3067 if (dwErrorCode == ERROR_FILE_NOT_FOUND) 3068 { 3069 dwErrorCode = ERROR_INVALID_PRINTER_NAME; 3070 goto Cleanup; 3071 } 3072 else if (dwErrorCode != ERROR_SUCCESS) 3073 { 3074 ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode); 3075 goto Cleanup; 3076 } 3077 3078 cchPrinter = wcslen(pszPrinter); 3079 } 3080 else 3081 { 3082 // If there is already a default printer, we're done! 3083 cchPrinter = _countof(wszPrinter); 3084 if (GetDefaultPrinterW(wszPrinter, &cchPrinter)) 3085 { 3086 dwErrorCode = ERROR_SUCCESS; 3087 goto Cleanup; 3088 } 3089 3090 // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size. 3091 cchPrinter = _countof(wszPrinter); 3092 dwErrorCode = (DWORD)RegEnumValueW(hDevicesKey, 0, wszPrinter, &cchPrinter, NULL, NULL, NULL, &cbPrinterValueData); 3093 if (dwErrorCode != ERROR_MORE_DATA) 3094 goto Cleanup; 3095 3096 pszPrinter = wszPrinter; 3097 } 3098 3099 // We now need to query the value data, which has the format "winspool,<Port>:" 3100 // and make "<Printer Name>,winspool,<Port>:" out of it. 3101 // Allocate a buffer large enough for the final data. 3102 cbDeviceValueData = (cchPrinter + 1) * sizeof(WCHAR) + cbPrinterValueData; 3103 pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData); 3104 if (!pwszDeviceValueData) 3105 { 3106 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 3107 ERR("HeapAlloc failed!\n"); 3108 goto Cleanup; 3109 } 3110 3111 // Copy the Printer Name and a comma into it. 3112 CopyMemory(pwszDeviceValueData, pszPrinter, cchPrinter * sizeof(WCHAR)); 3113 pwszDeviceValueData[cchPrinter] = L','; 3114 3115 // Append the value data, which has the format "winspool,<Port>:" 3116 dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, (PBYTE)&pwszDeviceValueData[cchPrinter + 1], &cbPrinterValueData); 3117 if (dwErrorCode != ERROR_SUCCESS) 3118 goto Cleanup; 3119 3120 // Open the Windows registry key. 3121 dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_SET_VALUE, &hWindowsKey); 3122 if (dwErrorCode != ERROR_SUCCESS) 3123 { 3124 ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode); 3125 goto Cleanup; 3126 } 3127 3128 // Store our new default printer. 3129 dwErrorCode = (DWORD)RegSetValueExW(hWindowsKey, wszDeviceValue, 0, REG_SZ, (PBYTE)pwszDeviceValueData, cbDeviceValueData); 3130 if (dwErrorCode != ERROR_SUCCESS) 3131 { 3132 ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode); 3133 goto Cleanup; 3134 } 3135 3136 Cleanup: 3137 if (hDevicesKey) 3138 RegCloseKey(hDevicesKey); 3139 3140 if (hWindowsKey) 3141 RegCloseKey(hWindowsKey); 3142 3143 if (pwszDeviceValueData) 3144 HeapFree(hProcessHeap, 0, pwszDeviceValueData); 3145 3146 SetLastError(dwErrorCode); 3147 return (dwErrorCode == ERROR_SUCCESS); 3148 } 3149 3150 BOOL WINAPI 3151 SetPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command) 3152 { 3153 BOOL Ret = FALSE; 3154 UNICODE_STRING usBuffer; 3155 PPRINTER_INFO_STRESS ppisa = (PPRINTER_INFO_STRESS)pPrinter; 3156 PPRINTER_INFO_STRESS ppisw = (PPRINTER_INFO_STRESS)pPrinter; 3157 PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter; 3158 PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter; 3159 PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter; 3160 PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter; 3161 PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter; 3162 PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter; 3163 PWSTR pwszPrinterName = NULL; 3164 PWSTR pwszServerName = NULL; 3165 PWSTR pwszShareName = NULL; 3166 PWSTR pwszPortName = NULL; 3167 PWSTR pwszDriverName = NULL; 3168 PWSTR pwszComment = NULL; 3169 PWSTR pwszLocation = NULL; 3170 PWSTR pwszSepFile = NULL; 3171 PWSTR pwszPrintProcessor = NULL; 3172 PWSTR pwszDatatype = NULL; 3173 PWSTR pwszParameters = NULL; 3174 PDEVMODEW pdmw = NULL; 3175 3176 FIXME("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command); 3177 3178 switch ( Level ) 3179 { 3180 case 0: 3181 if ( Command == 0 ) 3182 { 3183 if (ppisa->pPrinterName) 3184 { 3185 pwszPrinterName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pPrinterName); 3186 if (!(ppisw->pPrinterName = pwszPrinterName)) goto Cleanup; 3187 } 3188 if (ppisa->pServerName) 3189 { 3190 pwszServerName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pServerName); 3191 if (!(ppisw->pPrinterName = pwszServerName)) goto Cleanup; 3192 } 3193 } 3194 if ( Command == PRINTER_CONTROL_SET_STATUS ) 3195 { 3196 // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status. 3197 PRINTER_INFO_6 pi6; 3198 pi6.dwStatus = (DWORD_PTR)pPrinter; 3199 pPrinter = (LPBYTE)&pi6; 3200 Level = 6; 3201 Command = 0; 3202 } 3203 break; 3204 case 2: 3205 { 3206 if (ppi2a->pShareName) 3207 { 3208 pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName); 3209 if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup; 3210 } 3211 if (ppi2a->pPortName) 3212 { 3213 pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName); 3214 if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup; 3215 } 3216 if (ppi2a->pDriverName) 3217 { 3218 pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName); 3219 if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup; 3220 } 3221 if (ppi2a->pComment) 3222 { 3223 pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment); 3224 if (!(ppi2w->pComment = pwszComment)) goto Cleanup; 3225 } 3226 if (ppi2a->pLocation) 3227 { 3228 pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation); 3229 if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup; 3230 } 3231 if (ppi2a->pSepFile) 3232 { 3233 pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile); 3234 if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup; 3235 } 3236 if (ppi2a->pServerName) 3237 { 3238 pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor); 3239 if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup; 3240 } 3241 if (ppi2a->pDatatype) 3242 { 3243 pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype); 3244 if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup; 3245 } 3246 if (ppi2a->pParameters) 3247 { 3248 pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters); 3249 if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup; 3250 } 3251 3252 if ( ppi2a->pDevMode ) 3253 { 3254 RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw ); 3255 ppi2w->pDevMode = pdmw; 3256 } 3257 } 3258 // 3259 // These two strings are relitive and common to these three Levels. 3260 // Fall through... 3261 // 3262 case 4: 3263 case 5: 3264 { 3265 if (ppi2a->pServerName) // 4 & 5 : pPrinterName. 3266 { 3267 pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName); 3268 if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup; 3269 } 3270 if (ppi2a->pPrinterName) // 4 : pServerName, 5 : pPortName. 3271 { 3272 pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName); 3273 if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup; 3274 } 3275 } 3276 break; 3277 case 3: 3278 case 6: 3279 break; 3280 case 7: 3281 { 3282 if (ppi7a->pszObjectGUID) 3283 { 3284 pwszPrinterName = AsciiToUnicode(&usBuffer, ppi7a->pszObjectGUID); 3285 if (!(ppi7w->pszObjectGUID = pwszPrinterName)) goto Cleanup; 3286 } 3287 } 3288 break; 3289 3290 case 8: 3291 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */ 3292 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */ 3293 /* fall through */ 3294 case 9: 3295 { 3296 RosConvertAnsiDevModeToUnicodeDevmode( ppi9a->pDevMode, &pdmw ); 3297 ppi9w->pDevMode = pdmw; 3298 } 3299 break; 3300 3301 default: 3302 FIXME( "Unsupported level %d\n", Level); 3303 SetLastError( ERROR_INVALID_LEVEL ); 3304 } 3305 3306 Ret = SetPrinterW( hPrinter, Level, pPrinter, Command ); 3307 3308 Cleanup: 3309 if (pdmw) HeapFree(hProcessHeap, 0, pdmw); 3310 if (pwszPrinterName) HeapFree(hProcessHeap, 0, pwszPrinterName); 3311 if (pwszServerName) HeapFree(hProcessHeap, 0, pwszServerName); 3312 if (pwszShareName) HeapFree(hProcessHeap, 0, pwszShareName); 3313 if (pwszPortName) HeapFree(hProcessHeap, 0, pwszPortName); 3314 if (pwszDriverName) HeapFree(hProcessHeap, 0, pwszDriverName); 3315 if (pwszComment) HeapFree(hProcessHeap, 0, pwszComment); 3316 if (pwszLocation) HeapFree(hProcessHeap, 0, pwszLocation); 3317 if (pwszSepFile) HeapFree(hProcessHeap, 0, pwszSepFile); 3318 if (pwszPrintProcessor) HeapFree(hProcessHeap, 0, pwszPrintProcessor); 3319 if (pwszDatatype) HeapFree(hProcessHeap, 0, pwszDatatype); 3320 if (pwszParameters) HeapFree(hProcessHeap, 0, pwszParameters); 3321 return Ret; 3322 } 3323 3324 BOOL WINAPI 3325 SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command) 3326 { 3327 DWORD dwErrorCode; 3328 WINSPOOL_PRINTER_CONTAINER PrinterContainer; 3329 WINSPOOL_DEVMODE_CONTAINER DevModeContainer; 3330 WINSPOOL_SECURITY_CONTAINER SecurityContainer; 3331 SECURITY_DESCRIPTOR *sd = NULL; 3332 DWORD size; 3333 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 3334 3335 FIXME("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command); 3336 3337 // Sanity checks 3338 if (!pHandle) 3339 return ERROR_INVALID_HANDLE; 3340 3341 DevModeContainer.cbBuf = 0; 3342 DevModeContainer.pDevMode = NULL; 3343 3344 SecurityContainer.cbBuf = 0; 3345 SecurityContainer.pSecurity = NULL; 3346 3347 switch ( Level ) 3348 { 3349 case 0: 3350 if ( Command == PRINTER_CONTROL_SET_STATUS ) 3351 { 3352 // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status. 3353 PRINTER_INFO_6 pi6; 3354 pi6.dwStatus = (DWORD_PTR)pPrinter; 3355 pPrinter = (LPBYTE)&pi6; 3356 Level = 6; 3357 Command = 0; 3358 } 3359 break; 3360 case 2: 3361 { 3362 PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter; 3363 if ( pi2w ) 3364 { 3365 if ( pi2w->pDevMode ) 3366 { 3367 if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) ) 3368 { 3369 DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra; 3370 DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode; 3371 } 3372 } 3373 3374 if ( pi2w->pSecurityDescriptor ) 3375 { 3376 sd = get_sd( pi2w->pSecurityDescriptor, &size ); 3377 if ( sd ) 3378 { 3379 SecurityContainer.cbBuf = size; 3380 SecurityContainer.pSecurity = (PBYTE)sd; 3381 } 3382 } 3383 } 3384 else 3385 { 3386 SetLastError(ERROR_INVALID_PARAMETER); 3387 return FALSE; 3388 } 3389 } 3390 break; 3391 case 3: 3392 { 3393 PPRINTER_INFO_3 pi3 = (PPRINTER_INFO_3)pPrinter; 3394 if ( pi3 ) 3395 { 3396 if ( pi3->pSecurityDescriptor ) 3397 { 3398 sd = get_sd( pi3->pSecurityDescriptor, &size ); 3399 if ( sd ) 3400 { 3401 SecurityContainer.cbBuf = size; 3402 SecurityContainer.pSecurity = (PBYTE)sd; 3403 } 3404 } 3405 } 3406 else 3407 { 3408 SetLastError(ERROR_INVALID_PARAMETER); 3409 return FALSE; 3410 } 3411 } 3412 break; 3413 3414 case 4: 3415 case 5: 3416 case 6: 3417 case 7: 3418 if ( pPrinter == NULL ) 3419 { 3420 SetLastError(ERROR_INVALID_PARAMETER); 3421 return FALSE; 3422 } 3423 break; 3424 3425 case 8: 3426 /* 8 is the global default printer info and 9 already sets it instead of the per-user one */ 3427 /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */ 3428 /* fall through */ 3429 case 9: 3430 { 3431 PPRINTER_INFO_9W pi9w = (PPRINTER_INFO_9W)pPrinter; 3432 if ( pi9w ) 3433 { 3434 if ( pi9w->pDevMode ) 3435 { 3436 if ( IsValidDevmodeNoSizeW( pi9w->pDevMode ) ) 3437 { 3438 DevModeContainer.cbBuf = pi9w->pDevMode->dmSize + pi9w->pDevMode->dmDriverExtra; 3439 DevModeContainer.pDevMode = (LPBYTE)pi9w->pDevMode; 3440 } 3441 } 3442 } 3443 } 3444 break; 3445 3446 default: 3447 FIXME( "Unsupported level %d\n", Level ); 3448 SetLastError( ERROR_INVALID_LEVEL ); 3449 return FALSE; 3450 } 3451 3452 PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter; 3453 PrinterContainer.Level = Level; 3454 3455 // Do the RPC call 3456 RpcTryExcept 3457 { 3458 dwErrorCode = _RpcSetPrinter(pHandle->hPrinter, &PrinterContainer, &DevModeContainer, &SecurityContainer, Command); 3459 } 3460 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 3461 { 3462 dwErrorCode = RpcExceptionCode(); 3463 } 3464 RpcEndExcept; 3465 3466 if ( sd ) HeapFree( GetProcessHeap(), 0, sd ); 3467 3468 SetLastError(dwErrorCode); 3469 return (dwErrorCode == ERROR_SUCCESS); 3470 } 3471 3472 BOOL WINAPI 3473 SplDriverUnloadComplete(LPWSTR pDriverFile) 3474 { 3475 TRACE("DriverUnloadComplete(%S)\n", pDriverFile); 3476 UNIMPLEMENTED; 3477 return TRUE; // return true for now. 3478 } 3479 BOOL WINAPI 3480 3481 SpoolerPrinterEvent( LPWSTR pPrinterName, INT DriverEvent, DWORD Flags, LPARAM lParam ) 3482 { 3483 HMODULE hLibrary; 3484 HANDLE hPrinter; 3485 BOOL Ret = FALSE; 3486 3487 if ( OpenPrinterW( pPrinterName, &hPrinter, NULL ) ) 3488 { 3489 hLibrary = LoadPrinterDriver( hPrinter ); 3490 3491 if ( hLibrary ) 3492 { 3493 fpPrinterEvent = (PVOID)GetProcAddress( hLibrary, "DrvPrinterEvent" ); 3494 3495 if ( fpPrinterEvent ) 3496 { 3497 Ret = fpPrinterEvent( pPrinterName, DriverEvent, Flags, lParam ); 3498 } 3499 3500 FreeLibrary(hLibrary); 3501 } 3502 3503 ClosePrinter( hPrinter ); 3504 } 3505 3506 return Ret; 3507 } 3508 3509 INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) 3510 { 3511 LPWSTR filename; 3512 3513 switch(msg) 3514 { 3515 case WM_INITDIALOG: 3516 SetWindowLongPtrW(hwnd, DWLP_USER, lparam); 3517 return TRUE; 3518 3519 case WM_COMMAND: 3520 if(HIWORD(wparam) == BN_CLICKED) 3521 { 3522 if(LOWORD(wparam) == IDOK) 3523 { 3524 HANDLE hf; 3525 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0); 3526 LPWSTR *output; 3527 3528 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); 3529 if (!filename) 3530 { 3531 ERR("Failed to allocate filename of %u bytes\n", (len + 1) * sizeof(WCHAR)); 3532 return FALSE; 3533 } 3534 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1); 3535 3536 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES) 3537 { 3538 WCHAR caption[200], message[200]; 3539 int mb_ret; 3540 3541 LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption)); 3542 LoadStringW(hinstWinSpool, IDS_FILE_EXISTS, message, ARRAYSIZE(message)); 3543 mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION); 3544 if(mb_ret == IDCANCEL) 3545 { 3546 HeapFree(GetProcessHeap(), 0, filename); 3547 return TRUE; 3548 } 3549 } 3550 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 3551 if(hf == INVALID_HANDLE_VALUE) 3552 { 3553 WCHAR caption[200], message[200]; 3554 3555 LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption)); 3556 LoadStringW(hinstWinSpool, IDS_CANNOT_OPEN, message, ARRAYSIZE(message)); 3557 MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION); 3558 HeapFree(GetProcessHeap(), 0, filename); 3559 return TRUE; 3560 } 3561 CloseHandle(hf); 3562 DeleteFileW(filename); 3563 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER); 3564 *output = filename; 3565 EndDialog(hwnd, IDOK); 3566 return TRUE; 3567 } 3568 if(LOWORD(wparam) == IDCANCEL) 3569 { 3570 EndDialog(hwnd, IDCANCEL); 3571 return TRUE; 3572 } 3573 } 3574 return FALSE; 3575 } 3576 return FALSE; 3577 } 3578 3579 static const WCHAR FILE_Port[] = {'F','I','L','E',':',0}; 3580 3581 LPWSTR WINAPI 3582 StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc ) 3583 { 3584 LPWSTR ret = NULL; 3585 DWORD len, attr, retDlg; 3586 3587 FIXME("StartDocDlgW(%p, %p)\n", hPrinter, doc); 3588 3589 if (doc->lpszOutput == NULL) /* Check whether default port is FILE: */ 3590 { 3591 PRINTER_INFO_5W *pi5; 3592 GetPrinterW(hPrinter, 5, NULL, 0, &len); 3593 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER) 3594 return NULL; 3595 pi5 = HeapAlloc(GetProcessHeap(), 0, len); 3596 if (!pi5) 3597 { 3598 ERR("Failed to allocate PRINTER_INFO_5W of %u bytes\n", len); 3599 return NULL; 3600 } 3601 3602 GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len); 3603 if (!pi5->pPortName || _wcsicmp(pi5->pPortName, FILE_Port)) 3604 { 3605 HeapFree(GetProcessHeap(), 0, pi5); 3606 return NULL; 3607 } 3608 HeapFree(GetProcessHeap(), 0, pi5); 3609 } 3610 3611 if (doc->lpszOutput == NULL || !_wcsicmp(doc->lpszOutput, FILE_Port)) 3612 { 3613 LPWSTR name; 3614 3615 retDlg = DialogBoxParamW( hinstWinSpool, 3616 MAKEINTRESOURCEW(FILENAME_DIALOG), 3617 GetForegroundWindow(), 3618 file_dlg_proc, 3619 (LPARAM)&name ); 3620 3621 if ( retDlg == IDOK ) 3622 { 3623 if (!(len = GetFullPathNameW(name, 0, NULL, NULL))) 3624 { 3625 HeapFree(GetProcessHeap(), 0, name); 3626 return NULL; 3627 } 3628 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 3629 if (!ret) 3630 { 3631 ERR("Failed to allocate path name buffer of %u bytes\n", len * sizeof(WCHAR)); 3632 HeapFree(GetProcessHeap(), 0, name); 3633 return NULL; 3634 } 3635 GetFullPathNameW(name, len, ret, NULL); 3636 HeapFree(GetProcessHeap(), 0, name); 3637 } 3638 else if ( retDlg == 0 ) // FALSE, some type of error occurred. 3639 { 3640 ret = (LPWSTR)SP_ERROR; 3641 } 3642 else if ( retDlg == IDCANCEL ) 3643 { 3644 SetLastError( ERROR_CANCELLED ); 3645 ret = (LPWSTR)SP_APPABORT; 3646 } 3647 return ret; 3648 } 3649 3650 if (!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL))) 3651 return NULL; 3652 3653 ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 3654 if (!ret) 3655 { 3656 ERR("Failed to allocate path name buffer of %u bytes\n", len * sizeof(WCHAR)); 3657 return NULL; 3658 } 3659 GetFullPathNameW(doc->lpszOutput, len, ret, NULL); 3660 3661 attr = GetFileAttributesW(ret); 3662 if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY)) 3663 { 3664 HeapFree(GetProcessHeap(), 0, ret); 3665 ret = NULL; 3666 } 3667 return ret; 3668 } 3669 3670 LPSTR WINAPI 3671 StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc ) 3672 { 3673 UNICODE_STRING usBuffer; 3674 DOCINFOW docW = { 0 }; 3675 LPWSTR retW; 3676 LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL; 3677 LPSTR ret = NULL; 3678 3679 docW.cbSize = sizeof(docW); 3680 if (doc->lpszDocName) 3681 { 3682 docnameW = AsciiToUnicode(&usBuffer, doc->lpszDocName); 3683 if (!(docW.lpszDocName = docnameW)) goto failed; 3684 } 3685 if (doc->lpszOutput) 3686 { 3687 outputW = AsciiToUnicode(&usBuffer, doc->lpszOutput); 3688 if (!(docW.lpszOutput = outputW)) goto failed; 3689 } 3690 if (doc->lpszDatatype) 3691 { 3692 datatypeW = AsciiToUnicode(&usBuffer, doc->lpszDatatype); 3693 if (!(docW.lpszDatatype = datatypeW)) goto failed; 3694 } 3695 docW.fwType = doc->fwType; 3696 3697 retW = StartDocDlgW(hPrinter, &docW); 3698 3699 if (retW) 3700 { 3701 DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL); 3702 ret = HeapAlloc(GetProcessHeap(), 0, len); 3703 if (ret) 3704 { 3705 WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL); 3706 } 3707 else 3708 { 3709 ERR("Failed to allocate path name buffer of %u bytes\n", len); 3710 } 3711 HeapFree(GetProcessHeap(), 0, retW); 3712 } 3713 3714 failed: 3715 if (datatypeW) HeapFree(GetProcessHeap(), 0, datatypeW); 3716 if (outputW) HeapFree(GetProcessHeap(), 0, outputW); 3717 if (docnameW) HeapFree(GetProcessHeap(), 0, docnameW); 3718 3719 return ret; 3720 } 3721 3722 DWORD WINAPI 3723 StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) 3724 { 3725 DOC_INFO_1W wDocInfo1 = { 0 }; 3726 DWORD cch; 3727 DWORD dwErrorCode; 3728 DWORD dwReturnValue = 0; 3729 PDOC_INFO_1A pDocInfo1 = (PDOC_INFO_1A)pDocInfo; 3730 3731 TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter, Level, pDocInfo); 3732 3733 // Only check the minimum required for accessing pDocInfo. 3734 // Additional sanity checks are done in StartDocPrinterW. 3735 if (!pDocInfo1) 3736 { 3737 dwErrorCode = ERROR_INVALID_PARAMETER; 3738 goto Cleanup; 3739 } 3740 3741 if (Level != 1) 3742 { 3743 ERR("Level = %d, unsupported!\n", Level); 3744 dwErrorCode = ERROR_INVALID_LEVEL; 3745 goto Cleanup; 3746 } 3747 3748 if (pDocInfo1->pDatatype) 3749 { 3750 // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype 3751 cch = strlen(pDocInfo1->pDatatype); 3752 3753 wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 3754 if (!wDocInfo1.pDatatype) 3755 { 3756 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 3757 ERR("HeapAlloc failed!\n"); 3758 goto Cleanup; 3759 } 3760 3761 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDatatype, -1, wDocInfo1.pDatatype, cch + 1); 3762 } 3763 3764 if (pDocInfo1->pDocName) 3765 { 3766 // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName 3767 cch = strlen(pDocInfo1->pDocName); 3768 3769 wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 3770 if (!wDocInfo1.pDocName) 3771 { 3772 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 3773 ERR("HeapAlloc failed!\n"); 3774 goto Cleanup; 3775 } 3776 3777 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDocName, -1, wDocInfo1.pDocName, cch + 1); 3778 } 3779 3780 if (pDocInfo1->pOutputFile) 3781 { 3782 // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile 3783 cch = strlen(pDocInfo1->pOutputFile); 3784 3785 wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR)); 3786 if (!wDocInfo1.pOutputFile) 3787 { 3788 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 3789 ERR("HeapAlloc failed!\n"); 3790 goto Cleanup; 3791 } 3792 3793 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pOutputFile, -1, wDocInfo1.pOutputFile, cch + 1); 3794 } 3795 3796 dwReturnValue = StartDocPrinterW(hPrinter, Level, (PBYTE)&wDocInfo1); 3797 dwErrorCode = GetLastError(); 3798 3799 Cleanup: 3800 if (wDocInfo1.pDatatype) 3801 HeapFree(hProcessHeap, 0, wDocInfo1.pDatatype); 3802 3803 if (wDocInfo1.pDocName) 3804 HeapFree(hProcessHeap, 0, wDocInfo1.pDocName); 3805 3806 if (wDocInfo1.pOutputFile) 3807 HeapFree(hProcessHeap, 0, wDocInfo1.pOutputFile); 3808 3809 SetLastError(dwErrorCode); 3810 return dwReturnValue; 3811 } 3812 3813 DWORD WINAPI 3814 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) 3815 { 3816 DWORD cbAddJobInfo1; 3817 DWORD cbNeeded; 3818 DWORD dwErrorCode; 3819 DWORD dwReturnValue = 0; 3820 PADDJOB_INFO_1W pAddJobInfo1 = NULL; 3821 PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo; 3822 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 3823 3824 TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter, Level, pDocInfo); 3825 3826 // Sanity checks. 3827 if (!pHandle) 3828 { 3829 dwErrorCode = ERROR_INVALID_HANDLE; 3830 goto Cleanup; 3831 } 3832 3833 if (!pDocInfo1) 3834 { 3835 dwErrorCode = ERROR_INVALID_PARAMETER; 3836 goto Cleanup; 3837 } 3838 3839 if (Level != 1) 3840 { 3841 ERR("Level = %d, unsupported!\n", Level); 3842 dwErrorCode = ERROR_INVALID_LEVEL; 3843 goto Cleanup; 3844 } 3845 3846 if (pHandle->bStartedDoc) 3847 { 3848 dwErrorCode = ERROR_INVALID_PRINTER_STATE; 3849 goto Cleanup; 3850 } 3851 3852 // Check if we want to redirect output into a file. 3853 if (pDocInfo1->pOutputFile) 3854 { 3855 // Do a StartDocPrinter RPC call in this case. 3856 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1); 3857 } 3858 else 3859 { 3860 // Allocate memory for the ADDJOB_INFO_1W structure and a path. 3861 cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR); 3862 pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1); 3863 if (!pAddJobInfo1) 3864 { 3865 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 3866 ERR("HeapAlloc failed!\n"); 3867 goto Cleanup; 3868 } 3869 3870 // Try to add a new job. 3871 // This only succeeds if the printer is set to do spooled printing. 3872 if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded)) 3873 { 3874 // Do spooled printing. 3875 dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1); 3876 } 3877 else if (GetLastError() == ERROR_INVALID_ACCESS) 3878 { 3879 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing. 3880 // In this case, we do a StartDocPrinter RPC call. 3881 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1); 3882 } 3883 else 3884 { 3885 dwErrorCode = GetLastError(); 3886 ERR("AddJobW failed with error %lu!\n", dwErrorCode); 3887 goto Cleanup; 3888 } 3889 } 3890 3891 if (dwErrorCode == ERROR_SUCCESS) 3892 { 3893 pHandle->bStartedDoc = TRUE; 3894 dwReturnValue = pHandle->dwJobID; 3895 if ( !pHandle->bTrayIcon ) 3896 { 3897 UpdateTrayIcon( hPrinter, pHandle->dwJobID ); 3898 } 3899 } 3900 3901 Cleanup: 3902 if (pAddJobInfo1) 3903 HeapFree(hProcessHeap, 0, pAddJobInfo1); 3904 3905 SetLastError(dwErrorCode); 3906 return dwReturnValue; 3907 } 3908 3909 BOOL WINAPI 3910 StartPagePrinter(HANDLE hPrinter) 3911 { 3912 DWORD dwErrorCode; 3913 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 3914 3915 TRACE("StartPagePrinter(%p)\n", hPrinter); 3916 3917 // Sanity checks. 3918 if (!pHandle) 3919 { 3920 dwErrorCode = ERROR_INVALID_HANDLE; 3921 goto Cleanup; 3922 } 3923 3924 // Do the RPC call 3925 RpcTryExcept 3926 { 3927 dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter); 3928 } 3929 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 3930 { 3931 dwErrorCode = RpcExceptionCode(); 3932 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode); 3933 } 3934 RpcEndExcept; 3935 3936 Cleanup: 3937 SetLastError(dwErrorCode); 3938 return (dwErrorCode == ERROR_SUCCESS); 3939 } 3940 3941 BOOL WINAPI 3942 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten) 3943 { 3944 DWORD dwErrorCode; 3945 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter; 3946 3947 TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pcWritten); 3948 3949 // Sanity checks. 3950 if (!pHandle) 3951 { 3952 dwErrorCode = ERROR_INVALID_HANDLE; 3953 goto Cleanup; 3954 } 3955 3956 if (!pHandle->bStartedDoc) 3957 { 3958 dwErrorCode = ERROR_SPL_NO_STARTDOC; 3959 goto Cleanup; 3960 } 3961 3962 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE) 3963 { 3964 // Write to the spool file. This doesn't need an RPC request. 3965 if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL)) 3966 { 3967 dwErrorCode = GetLastError(); 3968 ERR("WriteFile failed with error %lu!\n", dwErrorCode); 3969 goto Cleanup; 3970 } 3971 3972 dwErrorCode = ERROR_SUCCESS; 3973 } 3974 else 3975 { 3976 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed. 3977 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full. 3978 3979 // Do the RPC call 3980 RpcTryExcept 3981 { 3982 dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten); 3983 } 3984 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 3985 { 3986 dwErrorCode = RpcExceptionCode(); 3987 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode); 3988 } 3989 RpcEndExcept; 3990 } 3991 3992 Cleanup: 3993 SetLastError(dwErrorCode); 3994 return (dwErrorCode == ERROR_SUCCESS); 3995 } 3996 3997 BOOL WINAPI 3998 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus) 3999 { 4000 DWORD dwErrorCode, Bogus = 0; 4001 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hXcv; 4002 4003 TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus); 4004 4005 if ( pcbOutputNeeded == NULL ) 4006 { 4007 dwErrorCode = ERROR_INVALID_PARAMETER; 4008 goto Cleanup; 4009 } 4010 4011 // Sanity checks. 4012 if (!pHandle) // ( IntProtectHandle( hXcv, FALSE ) ) 4013 { 4014 dwErrorCode = ERROR_INVALID_HANDLE; 4015 goto Cleanup; 4016 } 4017 4018 // 4019 // Do fixups. 4020 // 4021 if ( pInputData == NULL ) 4022 { 4023 if ( !cbInputData ) 4024 { 4025 pInputData = (PBYTE)&Bogus; 4026 } 4027 } 4028 4029 if ( pOutputData == NULL ) 4030 { 4031 if ( !cbOutputData ) 4032 { 4033 pOutputData = (PBYTE)&Bogus; 4034 } 4035 } 4036 4037 // Do the RPC call 4038 RpcTryExcept 4039 { 4040 dwErrorCode = _RpcXcvData( pHandle->hPrinter, 4041 pszDataName, 4042 pInputData, 4043 cbInputData, 4044 pOutputData, 4045 cbOutputData, 4046 pcbOutputNeeded, 4047 pdwStatus ); 4048 } 4049 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 4050 { 4051 dwErrorCode = RpcExceptionCode(); 4052 ERR("_RpcXcvData failed with exception code %lu!\n", dwErrorCode); 4053 } 4054 RpcEndExcept; 4055 4056 //IntUnprotectHandle( hXcv ); 4057 4058 Cleanup: 4059 SetLastError(dwErrorCode); 4060 return (dwErrorCode == ERROR_SUCCESS); 4061 } 4062 4063 HANDLE 4064 WINAPI 4065 CreatePrinterIC( 4066 _In_ HANDLE hPrinter, 4067 _In_opt_ LPDEVMODEW pDevMode) 4068 { 4069 UNIMPLEMENTED; 4070 return NULL; 4071 } 4072 4073 BOOL 4074 WINAPI 4075 DeletePrinterIC( 4076 _In_ HANDLE hPrinterIC) 4077 { 4078 UNIMPLEMENTED; 4079 return FALSE; 4080 } 4081 4082 BOOL 4083 WINAPI 4084 PlayGdiScriptOnPrinterIC( 4085 _In_ HANDLE hPrinterIC, 4086 _In_reads_bytes_(cIn) LPBYTE pIn, 4087 _In_ DWORD cIn, 4088 _Out_writes_bytes_(cOut) LPBYTE pOut, 4089 _In_ DWORD cOut, 4090 _In_ DWORD ul) 4091 { 4092 UNIMPLEMENTED; 4093 return FALSE; 4094 } 4095