1 /* 2 * PROJECT: ReactOS Spooler Router 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Functions related to Printers and printing 5 * COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org) 6 */ 7 8 #include "precomp.h" 9 10 BOOL WINAPI 11 AbortPrinter(HANDLE hPrinter) 12 { 13 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 14 15 // Sanity checks. 16 if (!pHandle) 17 { 18 SetLastError(ERROR_INVALID_PARAMETER); 19 return FALSE; 20 } 21 22 return pHandle->pPrintProvider->PrintProvider.fpAbortPrinter(pHandle->hPrinter); 23 } 24 25 // 26 // See [MS-RPRN] 2.2.1.11 SPLCLIENT_INFO, SPLCLIENT_INFO Level. 27 // 28 HANDLE WINAPI 29 AddPrinterExW( PWSTR pName, DWORD Level, PBYTE pPrinter, PBYTE pClientInfo, DWORD ClientInfoLevel) 30 { 31 BOOL bReturnValue; 32 DWORD dwErrorCode = ERROR_INVALID_PRINTER_NAME; 33 HANDLE hPrinter = NULL; 34 PWSTR pPrinterName = NULL; 35 PLIST_ENTRY pEntry; 36 PSPOOLSS_PRINTER_HANDLE pHandle; 37 PSPOOLSS_PRINT_PROVIDER pPrintProvider; 38 39 if ( Level != 2 ) 40 { 41 FIXME( "Unsupported level %d\n", Level ); 42 SetLastError( ERROR_INVALID_LEVEL ); 43 return hPrinter; 44 } 45 else 46 { 47 PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter; 48 pPrinterName = pi2w->pPrinterName; 49 } 50 51 // Loop through all Print Providers to find one able to open this Printer. 52 for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink) 53 { 54 pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry); 55 56 hPrinter = pPrintProvider->PrintProvider.fpAddPrinterEx(pName, Level, pPrinter, pClientInfo, ClientInfoLevel); 57 58 bReturnValue = GetLastError(); 59 60 // Fallback.... ? 61 62 if ( hPrinter == NULL && bReturnValue == ERROR_NOT_SUPPORTED ) 63 { 64 hPrinter = pPrintProvider->PrintProvider.fpAddPrinter(pName, Level, pPrinter); 65 } 66 67 bReturnValue = GetLastError(); 68 69 if ( bReturnValue == ROUTER_SUCCESS && hPrinter ) 70 { 71 // This Print Provider has opened this Printer. 72 // Store this information and return a handle. 73 pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE)); 74 if (!pHandle) 75 { 76 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 77 ERR("DllAllocSplMem failed!\n"); 78 goto Cleanup; 79 } 80 81 pHandle->pPrintProvider = pPrintProvider; 82 pHandle->hPrinter = hPrinter; 83 84 dwErrorCode = ERROR_SUCCESS; 85 goto Cleanup; 86 } 87 else if (bReturnValue == ROUTER_STOP_ROUTING) 88 { 89 ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pPrinterName); 90 dwErrorCode = GetLastError(); 91 goto Cleanup; 92 } 93 } 94 95 Cleanup: 96 // ERROR_INVALID_NAME by the Print Provider is translated to ERROR_INVALID_PRINTER_NAME here, but not in other APIs as far as I know. 97 if (dwErrorCode == ERROR_INVALID_NAME) 98 dwErrorCode = ERROR_INVALID_PRINTER_NAME; 99 100 SetLastError(dwErrorCode); 101 return hPrinter; 102 } 103 104 HANDLE WINAPI 105 AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter) 106 { 107 BOOL bReturnValue; 108 DWORD dwErrorCode = ERROR_INVALID_PRINTER_NAME; 109 HANDLE hPrinter = NULL; 110 PWSTR pPrinterName = NULL; 111 PLIST_ENTRY pEntry; 112 PSPOOLSS_PRINTER_HANDLE pHandle; 113 PSPOOLSS_PRINT_PROVIDER pPrintProvider; 114 115 FIXME("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter); 116 117 if ( Level != 2 ) 118 { 119 FIXME( "Unsupported level %d\n", Level ); 120 SetLastError( ERROR_INVALID_LEVEL ); 121 return hPrinter; 122 } 123 else 124 { 125 PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter; 126 pPrinterName = pi2w->pPrinterName; 127 } 128 129 // Xp return AddPrinterExW( pName, Level, pPrinter, NULL, 0); but,,,, W7u just Forward Direct. 130 131 // Loop through all Print Providers to find one able to open this Printer. 132 for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink) 133 { 134 pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry); 135 136 hPrinter = pPrintProvider->PrintProvider.fpAddPrinter(pName, Level, pPrinter); 137 138 bReturnValue = GetLastError(); 139 140 if ( bReturnValue == ROUTER_SUCCESS && hPrinter ) 141 { 142 // This Print Provider has opened this Printer. 143 // Store this information and return a handle. 144 pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE)); 145 if (!pHandle) 146 { 147 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 148 ERR("DllAllocSplMem failed!\n"); 149 goto Cleanup; 150 } 151 152 pHandle->pPrintProvider = pPrintProvider; 153 pHandle->hPrinter = hPrinter; 154 155 dwErrorCode = ERROR_SUCCESS; 156 goto Cleanup; 157 } 158 else if (bReturnValue == ROUTER_STOP_ROUTING) 159 { 160 ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pPrinterName); 161 dwErrorCode = GetLastError(); 162 goto Cleanup; 163 } 164 } 165 166 Cleanup: 167 // ERROR_INVALID_NAME by the Print Provider is translated to ERROR_INVALID_PRINTER_NAME here, but not in other APIs as far as I know. 168 if (dwErrorCode == ERROR_INVALID_NAME) 169 dwErrorCode = ERROR_INVALID_PRINTER_NAME; 170 171 SetLastError(dwErrorCode); 172 return hPrinter; 173 } 174 175 BOOL WINAPI 176 ClosePrinter(HANDLE hPrinter) 177 { 178 BOOL bReturnValue; 179 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 180 181 FIXME("ClosePrinter %p\n",hPrinter); 182 183 // Sanity checks. 184 if (!pHandle) 185 { 186 SetLastError(ERROR_INVALID_PARAMETER); 187 return FALSE; 188 } 189 190 // FIXME: Call FindClosePrinterChangeNotification for all created change notifications (according to MSDN). 191 192 // Call CloseHandle of the Print Provider. 193 bReturnValue = pHandle->pPrintProvider->PrintProvider.fpClosePrinter(pHandle->hPrinter); 194 FIXME("ClosePrinter 2\n"); 195 // Free our handle information. 196 DllFreeSplMem(pHandle); 197 FIXME("ClosePrinter 3\n"); 198 return bReturnValue; 199 } 200 201 BOOL WINAPI 202 DeletePrinter(HANDLE hPrinter) 203 { 204 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 205 206 // Sanity checks. 207 if (!pHandle) 208 { 209 SetLastError(ERROR_INVALID_PARAMETER); 210 return FALSE; 211 } 212 213 return pHandle->pPrintProvider->PrintProvider.fpDeletePrinter(pHandle->hPrinter); 214 } 215 216 BOOL WINAPI 217 EndDocPrinter(HANDLE hPrinter) 218 { 219 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 220 221 // Sanity checks. 222 if (!pHandle) 223 { 224 SetLastError(ERROR_INVALID_PARAMETER); 225 return FALSE; 226 } 227 228 return pHandle->pPrintProvider->PrintProvider.fpEndDocPrinter(pHandle->hPrinter); 229 } 230 231 BOOL WINAPI 232 EndPagePrinter(HANDLE hPrinter) 233 { 234 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 235 236 // Sanity checks. 237 if (!pHandle) 238 { 239 SetLastError(ERROR_INVALID_PARAMETER); 240 return FALSE; 241 } 242 243 return pHandle->pPrintProvider->PrintProvider.fpEndPagePrinter(pHandle->hPrinter); 244 } 245 246 BOOL WINAPI 247 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 248 { 249 DWORD cbCallBuffer; 250 DWORD cbNeeded; 251 DWORD dwErrorCode = MAXDWORD; 252 DWORD dwReturned; 253 PBYTE pCallBuffer; 254 BOOL Ret = FALSE; 255 PSPOOLSS_PRINT_PROVIDER pPrintProvider; 256 PLIST_ENTRY pEntry; 257 258 // Begin counting. 259 *pcbNeeded = 0; 260 *pcReturned = 0; 261 262 if (cbBuf && !pPrinterEnum) 263 { 264 dwErrorCode = ERROR_INVALID_USER_BUFFER; 265 goto Cleanup; 266 } 267 268 // At the beginning, we have the full buffer available. 269 cbCallBuffer = cbBuf; 270 pCallBuffer = pPrinterEnum; 271 272 // Loop through all Print Providers. 273 for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink) 274 { 275 pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry); 276 277 // Call the EnumPrinters function of this Print Provider. 278 cbNeeded = 0; 279 dwReturned = 0; 280 Ret = pPrintProvider->PrintProvider.fpEnumPrinters(Flags, Name, Level, pCallBuffer, cbCallBuffer, &cbNeeded, &dwReturned); 281 282 if ( !Ret ) 283 { 284 dwErrorCode = GetLastError(); 285 } 286 287 // Add the returned counts to the total values. 288 *pcbNeeded += cbNeeded; 289 *pcReturned += dwReturned; 290 291 // Reduce the available buffer size for the next call without risking an underflow. 292 if (cbNeeded < cbCallBuffer) 293 cbCallBuffer -= cbNeeded; 294 else 295 cbCallBuffer = 0; 296 297 // Advance the buffer if the caller provided it. 298 if (pCallBuffer) 299 pCallBuffer += cbNeeded; 300 301 // dwErrorCode shall not be overwritten if a previous EnumPrinters call already succeeded. 302 if (dwErrorCode != ERROR_SUCCESS) 303 dwErrorCode = GetLastError(); 304 } 305 306 Cleanup: 307 SetLastError(dwErrorCode); 308 return (dwErrorCode == ERROR_SUCCESS); 309 } 310 311 BOOL WINAPI 312 GetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD cbBuf, PDWORD pcbNeeded) 313 { 314 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 315 316 // Sanity checks. 317 if (!pHandle) 318 { 319 SetLastError(ERROR_INVALID_PARAMETER); 320 return FALSE; 321 } 322 323 return pHandle->pPrintProvider->PrintProvider.fpGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 324 } 325 326 // 327 // Forward Dead API to Local/Remote.... 328 // 329 DWORD WINAPI 330 PrinterMessageBoxW(HANDLE hPrinter, DWORD Error, HWND hWnd, LPWSTR pText, LPWSTR pCaption, DWORD dwType) 331 { 332 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 333 334 // Sanity checks. 335 if (!pHandle) 336 { 337 SetLastError(ERROR_INVALID_PARAMETER); 338 return FALSE; 339 } 340 341 return pHandle->pPrintProvider->PrintProvider.fpPrinterMessageBox(pHandle->hPrinter, Error, hWnd, pText, pCaption, dwType); 342 } 343 344 BOOL WINAPI 345 OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault) 346 { 347 BOOL bReturnValue; 348 DWORD dwErrorCode = ERROR_INVALID_PRINTER_NAME; 349 HANDLE hPrinter; 350 PLIST_ENTRY pEntry; 351 PSPOOLSS_PRINTER_HANDLE pHandle; 352 PSPOOLSS_PRINT_PROVIDER pPrintProvider; 353 354 // Loop through all Print Providers to find one able to open this Printer. 355 for (pEntry = PrintProviderList.Flink; pEntry != &PrintProviderList; pEntry = pEntry->Flink) 356 { 357 pPrintProvider = CONTAINING_RECORD(pEntry, SPOOLSS_PRINT_PROVIDER, Entry); 358 359 bReturnValue = pPrintProvider->PrintProvider.fpOpenPrinter(pPrinterName, &hPrinter, pDefault); 360 if (bReturnValue == ROUTER_SUCCESS) 361 { 362 // This Print Provider has opened this Printer. 363 // Store this information and return a handle. 364 pHandle = DllAllocSplMem(sizeof(SPOOLSS_PRINTER_HANDLE)); 365 if (!pHandle) 366 { 367 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 368 ERR("DllAllocSplMem failed!\n"); 369 goto Cleanup; 370 } 371 372 pHandle->pPrintProvider = pPrintProvider; 373 pHandle->hPrinter = hPrinter; 374 *phPrinter = (HANDLE)pHandle; 375 376 dwErrorCode = ERROR_SUCCESS; 377 goto Cleanup; 378 } 379 else if (bReturnValue == ROUTER_STOP_ROUTING) 380 { 381 ERR("A Print Provider returned ROUTER_STOP_ROUTING for Printer \"%S\"!\n", pPrinterName); 382 dwErrorCode = GetLastError(); 383 goto Cleanup; 384 } 385 } 386 387 Cleanup: 388 // ERROR_INVALID_NAME by the Print Provider is translated to ERROR_INVALID_PRINTER_NAME here, but not in other APIs as far as I know. 389 if (dwErrorCode == ERROR_INVALID_NAME) 390 dwErrorCode = ERROR_INVALID_PRINTER_NAME; 391 392 SetLastError(dwErrorCode); 393 return (dwErrorCode == ERROR_SUCCESS); 394 } 395 396 BOOL WINAPI 397 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead) 398 { 399 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 400 401 // Sanity checks. 402 if (!pHandle) 403 { 404 SetLastError(ERROR_INVALID_PARAMETER); 405 return FALSE; 406 } 407 408 return pHandle->pPrintProvider->PrintProvider.fpReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead); 409 } 410 411 BOOL WINAPI 412 SeekPrinter( HANDLE hPrinter, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER pliNewPointer, DWORD dwMoveMethod, BOOL bWrite ) 413 { 414 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 415 416 // Sanity checks. 417 if (!pHandle) 418 { 419 SetLastError(ERROR_INVALID_PARAMETER); 420 return FALSE; 421 } 422 423 return pHandle->pPrintProvider->PrintProvider.fpSeekPrinter( pHandle->hPrinter, liDistanceToMove, pliNewPointer, dwMoveMethod, bWrite ); 424 } 425 426 BOOL WINAPI 427 SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command) 428 { 429 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 430 431 // Sanity checks. 432 if (!pHandle) 433 { 434 SetLastError(ERROR_INVALID_PARAMETER); 435 return FALSE; 436 } 437 438 return pHandle->pPrintProvider->PrintProvider.fpSetPrinter( pHandle->hPrinter, Level, pPrinter, Command ); 439 } 440 441 DWORD WINAPI 442 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) 443 { 444 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 445 446 // Sanity checks. 447 if (!pHandle) 448 { 449 SetLastError(ERROR_INVALID_PARAMETER); 450 return FALSE; 451 } 452 453 return pHandle->pPrintProvider->PrintProvider.fpStartDocPrinter(pHandle->hPrinter, Level, pDocInfo); 454 } 455 456 BOOL WINAPI 457 StartPagePrinter(HANDLE hPrinter) 458 { 459 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 460 461 // Sanity checks. 462 if (!pHandle) 463 { 464 SetLastError(ERROR_INVALID_PARAMETER); 465 return FALSE; 466 } 467 468 return pHandle->pPrintProvider->PrintProvider.fpStartPagePrinter(pHandle->hPrinter); 469 } 470 471 BOOL WINAPI 472 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten) 473 { 474 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hPrinter; 475 476 // Sanity checks. 477 if (!pHandle) 478 { 479 SetLastError(ERROR_INVALID_PARAMETER); 480 return FALSE; 481 } 482 483 return pHandle->pPrintProvider->PrintProvider.fpWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten); 484 } 485 486 BOOL WINAPI 487 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus) 488 { 489 PSPOOLSS_PRINTER_HANDLE pHandle = (PSPOOLSS_PRINTER_HANDLE)hXcv; 490 491 FIXME("XcvDataW( %p, %S,,,)\n",hXcv, pszDataName); 492 493 // Sanity checks. 494 if (!pHandle) 495 { 496 SetLastError(ERROR_INVALID_PARAMETER); 497 return FALSE; 498 } 499 500 return pHandle->pPrintProvider->PrintProvider.fpXcvData(pHandle->hPrinter, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus); 501 } 502