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