1 /* 2 * PROJECT: ReactOS Local Spooler 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 // Global Variables 11 SKIPLIST PrinterList; 12 13 // Forward Declarations 14 static void _LocalGetPrinterLevel0(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_STRESS* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName); 15 static void _LocalGetPrinterLevel1(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_1W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName); 16 static void _LocalGetPrinterLevel2(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_2W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName); 17 static void _LocalGetPrinterLevel3(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_3* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName); 18 static void _LocalGetPrinterLevel4(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_4W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName); 19 static void _LocalGetPrinterLevel5(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_5W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName); 20 static void _LocalGetPrinterLevel6(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_6* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName); 21 static void _LocalGetPrinterLevel7(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_7W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName); 22 static void _LocalGetPrinterLevel8(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_8W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName); 23 static void _LocalGetPrinterLevel9(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_9W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName); 24 25 // Local Constants 26 typedef void (*PLocalGetPrinterLevelFunc)(PLOCAL_PRINTER, PVOID, PBYTE*, PDWORD, DWORD, PCWSTR); 27 28 static const PLocalGetPrinterLevelFunc pfnGetPrinterLevels[] = { 29 (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel0, 30 (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel1, 31 (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel2, 32 (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel3, 33 (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel4, 34 (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel5, 35 (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel6, 36 (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel7, 37 (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel8, 38 (PLocalGetPrinterLevelFunc)&_LocalGetPrinterLevel9 39 }; 40 41 static DWORD dwPrinterInfo0Offsets[] = { 42 FIELD_OFFSET(PRINTER_INFO_STRESS, pPrinterName), 43 MAXDWORD 44 }; 45 46 static DWORD dwPrinterInfo1Offsets[] = { 47 FIELD_OFFSET(PRINTER_INFO_1W, pName), 48 FIELD_OFFSET(PRINTER_INFO_1W, pComment), 49 FIELD_OFFSET(PRINTER_INFO_1W, pDescription), 50 MAXDWORD 51 }; 52 53 static DWORD dwPrinterInfo2Offsets[] = { 54 FIELD_OFFSET(PRINTER_INFO_2W, pPrinterName), 55 FIELD_OFFSET(PRINTER_INFO_2W, pShareName), 56 FIELD_OFFSET(PRINTER_INFO_2W, pPortName), 57 FIELD_OFFSET(PRINTER_INFO_2W, pDriverName), 58 FIELD_OFFSET(PRINTER_INFO_2W, pComment), 59 FIELD_OFFSET(PRINTER_INFO_2W, pLocation), 60 FIELD_OFFSET(PRINTER_INFO_2W, pSepFile), 61 FIELD_OFFSET(PRINTER_INFO_2W, pPrintProcessor), 62 FIELD_OFFSET(PRINTER_INFO_2W, pDatatype), 63 FIELD_OFFSET(PRINTER_INFO_2W, pParameters), 64 MAXDWORD 65 }; 66 67 static DWORD dwPrinterInfo4Offsets[] = { 68 FIELD_OFFSET(PRINTER_INFO_4W, pPrinterName), 69 MAXDWORD 70 }; 71 72 static DWORD dwPrinterInfo5Offsets[] = { 73 FIELD_OFFSET(PRINTER_INFO_5W, pPrinterName), 74 FIELD_OFFSET(PRINTER_INFO_5W, pPortName), 75 MAXDWORD 76 }; 77 78 /** These values serve no purpose anymore, but are still used in PRINTER_INFO_5 and 79 HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts */ 80 static const DWORD dwDeviceNotSelectedTimeout = 15000; 81 static const DWORD dwTransmissionRetryTimeout = 45000; 82 83 84 /** 85 * @name _PrinterListCompareRoutine 86 * 87 * SKIPLIST_COMPARE_ROUTINE for the Printer List. 88 * Does a case-insensitive comparison, because e.g. LocalOpenPrinter doesn't match the case when looking for Printers. 89 */ 90 static int WINAPI 91 _PrinterListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct) 92 { 93 PLOCAL_PRINTER A = (PLOCAL_PRINTER)FirstStruct; 94 PLOCAL_PRINTER B = (PLOCAL_PRINTER)SecondStruct; 95 96 return wcsicmp(A->pwszPrinterName, B->pwszPrinterName); 97 } 98 99 /** 100 * @name InitializePrinterList 101 * 102 * Initializes a list of locally available Printers. 103 * The list is searchable by name and returns information about the printers, including their job queues. 104 * During this process, the job queues are also initialized. 105 */ 106 BOOL 107 InitializePrinterList(VOID) 108 { 109 DWORD cbData; 110 DWORD cchPrinterName; 111 DWORD dwErrorCode; 112 DWORD dwSubKeys; 113 DWORD i; 114 HKEY hSubKey = NULL; 115 PLOCAL_PORT pPort; 116 PLOCAL_PRINTER pPrinter = NULL; 117 PLOCAL_PRINT_PROCESSOR pPrintProcessor; 118 PWSTR pwszPort = NULL; 119 PWSTR pwszPrintProcessor = NULL; 120 WCHAR wszPrinterName[MAX_PRINTER_NAME + 1]; 121 122 TRACE("InitializePrinterList()\n"); 123 124 // Initialize an empty list for our printers. 125 InitializeSkiplist(&PrinterList, DllAllocSplMem, _PrinterListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem); 126 127 // Get the number of subkeys of the printers registry key. Each subkey is a local printer there. 128 dwErrorCode = (DWORD)RegQueryInfoKeyW(hPrintersKey, NULL, NULL, NULL, &dwSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 129 if (dwErrorCode != ERROR_SUCCESS) 130 { 131 ERR("RegQueryInfoKeyW failed with status %lu!\n", dwErrorCode); 132 goto Cleanup; 133 } 134 135 // Loop through all available local printers. 136 for (i = 0; i < dwSubKeys; i++) 137 { 138 // Cleanup tasks from the previous run 139 if (hSubKey) 140 { 141 RegCloseKey(hSubKey); 142 hSubKey = NULL; 143 } 144 145 if (pPrinter) 146 { 147 if (pPrinter->pDefaultDevMode) 148 DllFreeSplMem(pPrinter->pDefaultDevMode); 149 150 if (pPrinter->pwszDefaultDatatype) 151 DllFreeSplStr(pPrinter->pwszDefaultDatatype); 152 153 if (pPrinter->pwszDescription) 154 DllFreeSplStr(pPrinter->pwszDescription); 155 156 if (pPrinter->pwszPrinterDriver) 157 DllFreeSplStr(pPrinter->pwszPrinterDriver); 158 159 if (pPrinter->pwszPrinterName) 160 DllFreeSplStr(pPrinter->pwszPrinterName); 161 162 DllFreeSplMem(pPrinter); 163 pPrinter = NULL; 164 } 165 166 if (pwszPrintProcessor) 167 { 168 DllFreeSplStr(pwszPrintProcessor); 169 pwszPrintProcessor = NULL; 170 } 171 172 // Get the name of this printer. 173 cchPrinterName = _countof(wszPrinterName); 174 dwErrorCode = (DWORD)RegEnumKeyExW(hPrintersKey, i, wszPrinterName, &cchPrinterName, NULL, NULL, NULL, NULL); 175 if (dwErrorCode == ERROR_MORE_DATA) 176 { 177 // This printer name exceeds the maximum length and is invalid. 178 continue; 179 } 180 else if (dwErrorCode != ERROR_SUCCESS) 181 { 182 ERR("RegEnumKeyExW failed for iteration %lu with status %lu!\n", i, dwErrorCode); 183 continue; 184 } 185 186 // Open this Printer's registry key. 187 dwErrorCode = (DWORD)RegOpenKeyExW(hPrintersKey, wszPrinterName, 0, KEY_READ, &hSubKey); 188 if (dwErrorCode != ERROR_SUCCESS) 189 { 190 ERR("RegOpenKeyExW failed for Printer \"%S\" with status %lu!\n", wszPrinterName, dwErrorCode); 191 continue; 192 } 193 194 // Get the Print Processor. 195 pwszPrintProcessor = AllocAndRegQueryWSZ(hSubKey, L"Print Processor"); 196 if (!pwszPrintProcessor) 197 continue; 198 199 // Try to find it in the Print Processor List. 200 pPrintProcessor = FindPrintProcessor(pwszPrintProcessor); 201 if (!pPrintProcessor) 202 { 203 ERR("Invalid Print Processor \"%S\" for Printer \"%S\"!\n", pwszPrintProcessor, wszPrinterName); 204 continue; 205 } 206 207 // Get the Port. 208 pwszPort = AllocAndRegQueryWSZ(hSubKey, L"Port"); 209 if (!pwszPort) 210 continue; 211 212 // Try to find it in the Port List. 213 pPort = FindPort(pwszPort); 214 if (!pPort) 215 { 216 ERR("Invalid Port \"%S\" for Printer \"%S\"!\n", pwszPort, wszPrinterName); 217 continue; 218 } 219 220 // Create a new LOCAL_PRINTER structure for it. 221 pPrinter = DllAllocSplMem(sizeof(LOCAL_PRINTER)); 222 if (!pPrinter) 223 { 224 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 225 ERR("DllAllocSplMem failed!\n"); 226 goto Cleanup; 227 } 228 229 pPrinter->pwszPrinterName = AllocSplStr(wszPrinterName); 230 pPrinter->pPrintProcessor = pPrintProcessor; 231 pPrinter->pPort = pPort; 232 InitializePrinterJobList(pPrinter); 233 234 // Get the location. 235 pPrinter->pwszLocation = AllocAndRegQueryWSZ(hSubKey, L"Location"); 236 if (!pPrinter->pwszLocation) 237 continue; 238 239 // Get the printer driver. 240 pPrinter->pwszPrinterDriver = AllocAndRegQueryWSZ(hSubKey, L"Printer Driver"); 241 if (!pPrinter->pwszPrinterDriver) 242 continue; 243 244 // Get the description. 245 pPrinter->pwszDescription = AllocAndRegQueryWSZ(hSubKey, L"Description"); 246 if (!pPrinter->pwszDescription) 247 continue; 248 249 // Get the default datatype. 250 pPrinter->pwszDefaultDatatype = AllocAndRegQueryWSZ(hSubKey, L"Datatype"); 251 if (!pPrinter->pwszDefaultDatatype) 252 continue; 253 254 // Verify that it's valid. 255 if (!FindDatatype(pPrintProcessor, pPrinter->pwszDefaultDatatype)) 256 { 257 ERR("Invalid default datatype \"%S\" for Printer \"%S\"!\n", pPrinter->pwszDefaultDatatype, wszPrinterName); 258 continue; 259 } 260 261 // Determine the size of the DevMode. 262 dwErrorCode = (DWORD)RegQueryValueExW(hSubKey, L"Default DevMode", NULL, NULL, NULL, &cbData); 263 if (dwErrorCode != ERROR_SUCCESS) 264 { 265 ERR("Couldn't query the size of the DevMode for Printer \"%S\", status is %lu, cbData is %lu!\n", wszPrinterName, dwErrorCode, cbData); 266 continue; 267 } 268 269 // Allocate enough memory for the DevMode. 270 pPrinter->pDefaultDevMode = DllAllocSplMem(cbData); 271 if (!pPrinter->pDefaultDevMode) 272 { 273 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 274 ERR("DllAllocSplMem failed!\n"); 275 goto Cleanup; 276 } 277 278 // Get the default DevMode. 279 dwErrorCode = (DWORD)RegQueryValueExW(hSubKey, L"Default DevMode", NULL, NULL, (PBYTE)pPrinter->pDefaultDevMode, &cbData); 280 if (dwErrorCode != ERROR_SUCCESS) 281 { 282 ERR("Couldn't query a DevMode for Printer \"%S\", status is %lu, cbData is %lu!\n", wszPrinterName, dwErrorCode, cbData); 283 continue; 284 } 285 286 // Get the Attributes. 287 cbData = sizeof(DWORD); 288 dwErrorCode = (DWORD)RegQueryValueExW(hSubKey, L"Attributes", NULL, NULL, (PBYTE)&pPrinter->dwAttributes, &cbData); 289 if (dwErrorCode != ERROR_SUCCESS) 290 { 291 ERR("Couldn't query Attributes for Printer \"%S\", status is %lu!\n", wszPrinterName, dwErrorCode); 292 continue; 293 } 294 295 // Get the Status. 296 cbData = sizeof(DWORD); 297 dwErrorCode = (DWORD)RegQueryValueExW(hSubKey, L"Status", NULL, NULL, (PBYTE)&pPrinter->dwStatus, &cbData); 298 if (dwErrorCode != ERROR_SUCCESS) 299 { 300 ERR("Couldn't query Status for Printer \"%S\", status is %lu!\n", wszPrinterName, dwErrorCode); 301 continue; 302 } 303 304 // Add this printer to the printer list. 305 if (!InsertElementSkiplist(&PrinterList, pPrinter)) 306 { 307 ERR("InsertElementSkiplist failed for Printer \"%S\"!\n", pPrinter->pwszPrinterName); 308 goto Cleanup; 309 } 310 311 // Don't let the cleanup routines free this. 312 pPrinter = NULL; 313 } 314 315 dwErrorCode = ERROR_SUCCESS; 316 317 Cleanup: 318 // Inside the loop 319 if (hSubKey) 320 RegCloseKey(hSubKey); 321 322 if (pPrinter) 323 { 324 if (pPrinter->pDefaultDevMode) 325 DllFreeSplMem(pPrinter->pDefaultDevMode); 326 327 if (pPrinter->pwszDefaultDatatype) 328 DllFreeSplStr(pPrinter->pwszDefaultDatatype); 329 330 if (pPrinter->pwszDescription) 331 DllFreeSplStr(pPrinter->pwszDescription); 332 333 if (pPrinter->pwszPrinterDriver) 334 DllFreeSplStr(pPrinter->pwszPrinterDriver); 335 336 if (pPrinter->pwszPrinterName) 337 DllFreeSplStr(pPrinter->pwszPrinterName); 338 339 DllFreeSplMem(pPrinter); 340 } 341 342 if (pwszPrintProcessor) 343 DllFreeSplStr(pwszPrintProcessor); 344 345 SetLastError(dwErrorCode); 346 return (dwErrorCode == ERROR_SUCCESS); 347 } 348 349 /** 350 * @name _LocalEnumPrintersCheckName 351 * 352 * Checks the Name parameter supplied to a call to EnumPrinters. 353 * 354 * @param Flags 355 * Flags parameter of EnumPrinters. 356 * 357 * @param Name 358 * Name parameter of EnumPrinters to check. 359 * 360 * @param pwszComputerName 361 * Pointer to a string able to hold 2 + MAX_COMPUTERNAME_LENGTH + 1 + 1 characters. 362 * On return, it may contain a computer name to prepend in EnumPrinters depending on the case. 363 * 364 * @param pcchComputerName 365 * If a string to prepend is returned, this pointer receives its length in characters. 366 * 367 * @return 368 * ERROR_SUCCESS if processing in EnumPrinters can be continued. 369 * ERROR_INVALID_NAME if the Name parameter is invalid for the given flags and this Print Provider. 370 * Any other error code if GetComputerNameW fails. Error codes indicating failure should then be returned by EnumPrinters. 371 */ 372 static DWORD 373 _LocalEnumPrintersCheckName(DWORD Flags, PCWSTR Name, PWSTR pwszComputerName, PDWORD pcchComputerName) 374 { 375 PCWSTR pName; 376 PCWSTR pComputerName; 377 378 // If there is no Name parameter to check, we can just continue in EnumPrinters. 379 if (!Name) 380 return ERROR_SUCCESS; 381 382 // Check if Name does not begin with two backslashes (required for specifying Computer Names). 383 if (Name[0] != L'\\' || Name[1] != L'\\') 384 { 385 if (Flags & PRINTER_ENUM_NAME) 386 { 387 // If PRINTER_ENUM_NAME is specified, any given Name parameter may only contain the 388 // Print Provider Name or the local Computer Name. 389 390 // Compare with the Print Provider Name. 391 if (wcsicmp(Name, wszPrintProviderInfo[0]) == 0) 392 return ERROR_SUCCESS; 393 394 // Dismiss anything else. 395 return ERROR_INVALID_NAME; 396 } 397 else 398 { 399 // If PRINTER_ENUM_NAME is not specified, we just ignore anything that is not a Computer Name. 400 return ERROR_SUCCESS; 401 } 402 } 403 404 // Prepend the backslashes to the output computer name. 405 pwszComputerName[0] = L'\\'; 406 pwszComputerName[1] = L'\\'; 407 408 // Get the local computer name for comparison. 409 *pcchComputerName = MAX_COMPUTERNAME_LENGTH + 1; 410 if (!GetComputerNameW(&pwszComputerName[2], pcchComputerName)) 411 { 412 ERR("GetComputerNameW failed with error %lu!\n", GetLastError()); 413 return GetLastError(); 414 } 415 416 // Add the leading slashes to the total length. 417 *pcchComputerName += 2; 418 419 // Compare both names. 420 pComputerName = &pwszComputerName[2]; 421 pName = &Name[2]; 422 for (;;) 423 { 424 // Are we at the end of the local Computer Name string? 425 if (!*pComputerName) 426 { 427 // Are we also at the end of the supplied Name parameter? 428 // A terminating NUL character and a backslash are both treated as the end, but they are treated differently. 429 if (!*pName) 430 { 431 // If both names match and Name ends with a NUL character, the computer name will be prepended in EnumPrinters. 432 // Add a trailing backslash for that. 433 pwszComputerName[(*pcchComputerName)++] = L'\\'; 434 pwszComputerName[*pcchComputerName] = 0; 435 return ERROR_SUCCESS; 436 } 437 else if (*pName == L'\\') 438 { 439 if (Flags & PRINTER_ENUM_NAME) 440 { 441 // If PRINTER_ENUM_NAME is specified and a Name parameter is given, it must be exactly the local 442 // Computer Name with two backslashes prepended. Anything else (like "\\COMPUTERNAME\") is dismissed. 443 return ERROR_INVALID_NAME; 444 } 445 else 446 { 447 // If PRINTER_ENUM_NAME is not specified and a Name parameter is given, it may also end with a backslash. 448 // Only the Computer Name between the backslashes is checked then. 449 // This is largely undocumented, but verified by tests (see winspool_apitest). 450 // In this case, no computer name is prepended in EnumPrinters though. 451 *pwszComputerName = 0; 452 *pcchComputerName = 0; 453 return ERROR_SUCCESS; 454 } 455 } 456 } 457 458 // Compare both Computer Names case-insensitively and reject with ERROR_INVALID_NAME if they don't match. 459 if (towlower(*pName) != towlower(*pComputerName)) 460 return ERROR_INVALID_NAME; 461 462 pName++; 463 pComputerName++; 464 } 465 } 466 467 static DWORD 468 _DumpLevel1PrintProviderInformation(PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned) 469 { 470 int i; 471 472 // Count the needed bytes for Print Provider information. 473 *pcbNeeded = sizeof(PRINTER_INFO_1W); 474 475 for (i = 0; i < 3; i++) 476 *pcbNeeded += (wcslen(wszPrintProviderInfo[i]) + 1) * sizeof(WCHAR); 477 478 // Check if the supplied buffer is large enough. 479 if (cbBuf < *pcbNeeded) 480 return ERROR_INSUFFICIENT_BUFFER; 481 482 // Copy over the Print Provider information. 483 ((PPRINTER_INFO_1W)pPrinterEnum)->Flags = 0; 484 PackStrings(wszPrintProviderInfo, pPrinterEnum, dwPrinterInfo1Offsets, &pPrinterEnum[*pcbNeeded]); 485 *pcReturned = 1; 486 487 return ERROR_SUCCESS; 488 } 489 490 static void 491 _LocalGetPrinterLevel0(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_STRESS* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName) 492 { 493 size_t cbName; 494 PWSTR p; 495 PWSTR pwszStrings[1]; 496 SYSTEM_INFO SystemInfo; 497 498 // Calculate the string lengths. 499 cbName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); 500 501 if (!ppPrinterInfo) 502 { 503 *pcbNeeded += sizeof(PRINTER_INFO_STRESS) + cbName; 504 return; 505 } 506 507 // Set the general fields. 508 ZeroMemory(*ppPrinterInfo, sizeof(PRINTER_INFO_STRESS)); 509 (*ppPrinterInfo)->cJobs = pPrinter->JobList.NodeCount; 510 (*ppPrinterInfo)->dwGetVersion = GetVersion(); 511 (*ppPrinterInfo)->Status = pPrinter->dwStatus; 512 513 #if !defined(DBG) 514 (*ppPrinterInfo)->fFreeBuild = 1; 515 #endif 516 517 GetSystemInfo(&SystemInfo); 518 (*ppPrinterInfo)->dwNumberOfProcessors = SystemInfo.dwNumberOfProcessors; 519 (*ppPrinterInfo)->dwProcessorType = SystemInfo.dwProcessorType; 520 (*ppPrinterInfo)->wProcessorArchitecture = SystemInfo.wProcessorArchitecture; 521 (*ppPrinterInfo)->wProcessorLevel = SystemInfo.wProcessorLevel; 522 523 // Copy the Printer Name. 524 pwszStrings[0] = DllAllocSplMem(cbName); 525 p = pwszStrings[0]; 526 StringCbCopyExW(p, cbName, wszComputerName, &p, &cbName, 0); 527 StringCbCopyExW(p, cbName, pPrinter->pwszPrinterName, &p, &cbName, 0); 528 529 // Finally copy the structure and advance to the next one in the output buffer. 530 *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo0Offsets, *ppPrinterInfoEnd); 531 (*ppPrinterInfo)++; 532 533 // Free the memory for temporary strings. 534 DllFreeSplMem(pwszStrings[0]); 535 } 536 537 static void 538 _LocalGetPrinterLevel1(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_1W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName) 539 { 540 const WCHAR wszComma[] = L","; 541 542 size_t cbName; 543 size_t cbComment; 544 size_t cbDescription; 545 PWSTR p; 546 PWSTR pwszStrings[3]; 547 548 // Calculate the string lengths. 549 // Attention: pComment equals the "Description" registry value while pDescription is concatenated out of several strings. 550 // On top of this, the computer name is prepended to the printer name if the user supplied the local computer name during the query. 551 cbName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); 552 cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR); 553 cbDescription = cbName + (wcslen(pPrinter->pwszPrinterDriver) + 1 + wcslen(pPrinter->pwszLocation) + 1) * sizeof(WCHAR); 554 555 if (!ppPrinterInfo) 556 { 557 *pcbNeeded += sizeof(PRINTER_INFO_1W) + cbName + cbComment + cbDescription; 558 return; 559 } 560 561 // Indicate that this is a Printer. 562 (*ppPrinterInfo)->Flags = PRINTER_ENUM_ICON8; 563 564 // Copy the Printer Name. 565 pwszStrings[0] = DllAllocSplMem(cbName); 566 p = pwszStrings[0]; 567 StringCbCopyExW(p, cbName, wszComputerName, &p, &cbName, 0); 568 StringCbCopyExW(p, cbName, pPrinter->pwszPrinterName, &p, &cbName, 0); 569 570 // Copy the Printer comment (equals the "Description" registry value). 571 pwszStrings[1] = pPrinter->pwszDescription; 572 573 // Copy the description, which for PRINTER_INFO_1W has the form "Name,Printer Driver,Location" 574 pwszStrings[2] = DllAllocSplMem(cbDescription); 575 p = pwszStrings[2]; 576 StringCbCopyExW(p, cbDescription, wszComputerName, &p, &cbDescription, 0); 577 StringCbCopyExW(p, cbDescription, pPrinter->pwszPrinterName, &p, &cbDescription, 0); 578 StringCbCopyExW(p, cbDescription, wszComma, &p, &cbDescription, 0); 579 StringCbCopyExW(p, cbDescription, pPrinter->pwszPrinterDriver, &p, &cbDescription, 0); 580 StringCbCopyExW(p, cbDescription, wszComma, &p, &cbDescription, 0); 581 StringCbCopyExW(p, cbDescription, pPrinter->pwszLocation, &p, &cbDescription, 0); 582 583 // Finally copy the structure and advance to the next one in the output buffer. 584 *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo1Offsets, *ppPrinterInfoEnd); 585 (*ppPrinterInfo)++; 586 587 // Free the memory for temporary strings. 588 DllFreeSplMem(pwszStrings[0]); 589 DllFreeSplMem(pwszStrings[2]); 590 } 591 592 static void 593 _LocalGetPrinterLevel2(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_2W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName) 594 { 595 WCHAR wszEmpty[] = L""; 596 597 size_t cbDevMode; 598 size_t cbPrinterName; 599 size_t cbShareName; 600 size_t cbPortName; 601 size_t cbDriverName; 602 size_t cbComment; 603 size_t cbLocation; 604 size_t cbSepFile; 605 size_t cbPrintProcessor; 606 size_t cbDatatype; 607 size_t cbParameters; 608 PWSTR p; 609 PWSTR pwszStrings[10]; 610 611 // Calculate the string lengths. 612 cbDevMode = pPrinter->pDefaultDevMode->dmSize + pPrinter->pDefaultDevMode->dmDriverExtra; 613 cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); 614 615 if (!ppPrinterInfo) 616 { 617 // Attention: pComment equals the "Description" registry value. 618 cbShareName = sizeof(wszEmpty); 619 cbPortName = (wcslen(pPrinter->pPort->pwszName) + 1) * sizeof(WCHAR); 620 cbDriverName = (wcslen(pPrinter->pwszPrinterDriver) + 1) * sizeof(WCHAR); 621 cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR); 622 cbLocation = (wcslen(pPrinter->pwszLocation) + 1) * sizeof(WCHAR); 623 cbSepFile = sizeof(wszEmpty); 624 cbPrintProcessor = (wcslen(pPrinter->pPrintProcessor->pwszName) + 1) * sizeof(WCHAR); 625 cbDatatype = (wcslen(pPrinter->pwszDefaultDatatype) + 1) * sizeof(WCHAR); 626 cbParameters = sizeof(wszEmpty); 627 628 *pcbNeeded += sizeof(PRINTER_INFO_2W) + cbDevMode + cbPrinterName + cbShareName + cbPortName + cbDriverName + cbComment + cbLocation + cbSepFile + cbPrintProcessor + cbDatatype + cbParameters; 629 return; 630 } 631 632 // Set the general fields. 633 ZeroMemory(*ppPrinterInfo, sizeof(PRINTER_INFO_2W)); 634 (*ppPrinterInfo)->Attributes = pPrinter->dwAttributes; 635 (*ppPrinterInfo)->cJobs = pPrinter->JobList.NodeCount; 636 (*ppPrinterInfo)->Status = pPrinter->dwStatus; 637 638 // Set the pDevMode field (and copy the DevMode). 639 *ppPrinterInfoEnd -= cbDevMode; 640 CopyMemory(*ppPrinterInfoEnd, pPrinter->pDefaultDevMode, cbDevMode); 641 (*ppPrinterInfo)->pDevMode = (PDEVMODEW)(*ppPrinterInfoEnd); 642 643 // Set the pPrinterName field. 644 pwszStrings[0] = DllAllocSplMem(cbPrinterName); 645 p = pwszStrings[0]; 646 StringCbCopyExW(p, cbPrinterName, wszComputerName, &p, &cbPrinterName, 0); 647 StringCbCopyExW(p, cbPrinterName, pPrinter->pwszPrinterName, &p, &cbPrinterName, 0); 648 649 // Set the pShareName field. 650 pwszStrings[1] = wszEmpty; 651 652 // Set the pPortName field. 653 pwszStrings[2] = pPrinter->pPort->pwszName; 654 655 // Set the pDriverName field. 656 pwszStrings[3] = pPrinter->pwszPrinterDriver; 657 658 // Set the pComment field ((equals the "Description" registry value). 659 pwszStrings[4] = pPrinter->pwszDescription; 660 661 // Set the pLocation field. 662 pwszStrings[5] = pPrinter->pwszLocation; 663 664 // Set the pSepFile field. 665 pwszStrings[6] = wszEmpty; 666 667 // Set the pPrintProcessor field. 668 pwszStrings[7] = pPrinter->pPrintProcessor->pwszName; 669 670 // Set the pDatatype field. 671 pwszStrings[8] = pPrinter->pwszDefaultDatatype; 672 673 // Set the pParameters field. 674 pwszStrings[9] = wszEmpty; 675 676 // Finally copy the structure and advance to the next one in the output buffer. 677 *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo2Offsets, *ppPrinterInfoEnd); 678 (*ppPrinterInfo)++; 679 680 // Free the memory for temporary strings. 681 DllFreeSplMem(pwszStrings[0]); 682 } 683 684 static void 685 _LocalGetPrinterLevel3(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_3* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName) 686 { 687 SECURITY_DESCRIPTOR SecurityDescriptor = { 0 }; 688 689 if (!ppPrinterInfo) 690 { 691 *pcbNeeded += sizeof(PRINTER_INFO_3) + sizeof(SECURITY_DESCRIPTOR); 692 return; 693 } 694 695 FIXME("Return a valid security descriptor for PRINTER_INFO_3\n"); 696 697 // Set the pSecurityDescriptor field (and copy the Security Descriptor). 698 *ppPrinterInfoEnd -= sizeof(SECURITY_DESCRIPTOR); 699 CopyMemory(*ppPrinterInfoEnd, &SecurityDescriptor, sizeof(SECURITY_DESCRIPTOR)); 700 (*ppPrinterInfo)->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)(*ppPrinterInfoEnd); 701 702 // Advance to the next structure. 703 (*ppPrinterInfo)++; 704 } 705 706 static void 707 _LocalGetPrinterLevel4(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_4W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName) 708 { 709 size_t cbPrinterName; 710 PWSTR p; 711 PWSTR pwszStrings[1]; 712 713 // Calculate the string lengths. 714 cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); 715 716 if (!ppPrinterInfo) 717 { 718 *pcbNeeded += sizeof(PRINTER_INFO_4W) + cbPrinterName; 719 return; 720 } 721 722 // Set the general fields. 723 (*ppPrinterInfo)->pServerName = NULL; 724 (*ppPrinterInfo)->Attributes = pPrinter->dwAttributes; 725 726 // Set the pPrinterName field. 727 pwszStrings[0] = DllAllocSplMem(cbPrinterName); 728 p = pwszStrings[0]; 729 StringCbCopyExW(p, cbPrinterName, wszComputerName, &p, &cbPrinterName, 0); 730 StringCbCopyExW(p, cbPrinterName, pPrinter->pwszPrinterName, &p, &cbPrinterName, 0); 731 732 // Finally copy the structure and advance to the next one in the output buffer. 733 *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo4Offsets, *ppPrinterInfoEnd); 734 (*ppPrinterInfo)++; 735 736 // Free the memory for temporary strings. 737 DllFreeSplMem(pwszStrings[0]); 738 } 739 740 static void 741 _LocalGetPrinterLevel5(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_5W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName) 742 { 743 size_t cbPrinterName; 744 size_t cbPortName; 745 PWSTR p; 746 PWSTR pwszStrings[2]; 747 748 // Calculate the string lengths. 749 cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); 750 751 if (!ppPrinterInfo) 752 { 753 cbPortName = (wcslen(pPrinter->pPort->pwszName) + 1) * sizeof(WCHAR); 754 755 *pcbNeeded += sizeof(PRINTER_INFO_5W) + cbPrinterName + cbPortName; 756 return; 757 } 758 759 // Set the general fields. 760 (*ppPrinterInfo)->Attributes = pPrinter->dwAttributes; 761 (*ppPrinterInfo)->DeviceNotSelectedTimeout = dwDeviceNotSelectedTimeout; 762 (*ppPrinterInfo)->TransmissionRetryTimeout = dwTransmissionRetryTimeout; 763 764 // Set the pPrinterName field. 765 pwszStrings[0] = DllAllocSplMem(cbPrinterName); 766 p = pwszStrings[0]; 767 StringCbCopyExW(p, cbPrinterName, wszComputerName, &p, &cbPrinterName, 0); 768 StringCbCopyExW(p, cbPrinterName, pPrinter->pwszPrinterName, &p, &cbPrinterName, 0); 769 770 // Set the pPortName field. 771 pwszStrings[1] = pPrinter->pPort->pwszName; 772 773 // Finally copy the structure and advance to the next one in the output buffer. 774 *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo5Offsets, *ppPrinterInfoEnd); 775 (*ppPrinterInfo)++; 776 777 // Free the memory for temporary strings. 778 DllFreeSplMem(pwszStrings[0]); 779 } 780 781 static void 782 _LocalGetPrinterLevel6(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_6* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName) 783 { 784 if (!ppPrinterInfo) 785 { 786 *pcbNeeded += sizeof(PRINTER_INFO_6); 787 return; 788 } 789 790 // Set the general fields. 791 (*ppPrinterInfo)->dwStatus = pPrinter->dwStatus; 792 793 // Advance to the next structure. 794 (*ppPrinterInfo)++; 795 } 796 797 static void 798 _LocalGetPrinterLevel7(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_7W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName) 799 { 800 if (!ppPrinterInfo) 801 { 802 *pcbNeeded += sizeof(PRINTER_INFO_7W); 803 return; 804 } 805 806 FIXME("No Directory Support, returning DSPRINT_UNPUBLISH for PRINTER_INFO_7 all the time!\n"); 807 808 // Set the general fields. 809 (*ppPrinterInfo)->dwAction = DSPRINT_UNPUBLISH; 810 (*ppPrinterInfo)->pszObjectGUID = NULL; 811 812 // Advance to the next structure. 813 (*ppPrinterInfo)++; 814 } 815 816 static void 817 _LocalGetPrinterLevel8(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_8W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName) 818 { 819 DWORD cbDevMode; 820 821 // Calculate the string lengths. 822 cbDevMode = pPrinter->pDefaultDevMode->dmSize + pPrinter->pDefaultDevMode->dmDriverExtra; 823 824 if (!ppPrinterInfo) 825 { 826 *pcbNeeded += sizeof(PRINTER_INFO_8W) + cbDevMode; 827 return; 828 } 829 830 // Set the pDevMode field (and copy the DevMode). 831 *ppPrinterInfoEnd -= cbDevMode; 832 CopyMemory(*ppPrinterInfoEnd, pPrinter->pDefaultDevMode, cbDevMode); 833 (*ppPrinterInfo)->pDevMode = (PDEVMODEW)(*ppPrinterInfoEnd); 834 835 // Advance to the next structure. 836 (*ppPrinterInfo)++; 837 } 838 839 static void 840 _LocalGetPrinterLevel9(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_9W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName) 841 { 842 DWORD cbDevMode; 843 844 // Calculate the string lengths. 845 cbDevMode = pPrinter->pDefaultDevMode->dmSize + pPrinter->pDefaultDevMode->dmDriverExtra; 846 847 if (!ppPrinterInfo) 848 { 849 *pcbNeeded += sizeof(PRINTER_INFO_9W) + cbDevMode; 850 return; 851 } 852 853 FIXME("Per-user settings are not yet implemented, returning the global DevMode for PRINTER_INFO_9!\n"); 854 855 // Set the pDevMode field (and copy the DevMode). 856 *ppPrinterInfoEnd -= cbDevMode; 857 CopyMemory(*ppPrinterInfoEnd, pPrinter->pDefaultDevMode, cbDevMode); 858 (*ppPrinterInfo)->pDevMode = (PDEVMODEW)(*ppPrinterInfoEnd); 859 860 // Advance to the next structure. 861 (*ppPrinterInfo)++; 862 } 863 864 BOOL WINAPI 865 LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned) 866 { 867 DWORD cchComputerName = 0; 868 DWORD dwErrorCode; 869 PBYTE pPrinterInfoEnd; 870 PSKIPLIST_NODE pNode; 871 WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1] = { 0 }; 872 PLOCAL_PRINTER pPrinter; 873 874 TRACE("LocalEnumPrinters(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned); 875 876 // Do no sanity checks or assertions for pcbNeeded and pcReturned here. 877 // This is verified and required by localspl_apitest! 878 879 // Begin counting. 880 *pcbNeeded = 0; 881 *pcReturned = 0; 882 883 if (Flags & PRINTER_ENUM_CONNECTIONS || Flags & PRINTER_ENUM_REMOTE || Flags & PRINTER_ENUM_NETWORK) 884 { 885 // If the flags for the Network Print Provider are given, bail out with ERROR_INVALID_NAME. 886 // This is the internal way for a Print Provider to signal that it doesn't handle this request. 887 dwErrorCode = ERROR_INVALID_NAME; 888 goto Cleanup; 889 } 890 891 if (!(Flags & PRINTER_ENUM_LOCAL || Flags & PRINTER_ENUM_NAME)) 892 { 893 // The Local Print Provider is the right destination for the request, but without any of these flags, 894 // there is no information that can be returned. 895 // So just signal a successful request. 896 dwErrorCode = ERROR_SUCCESS; 897 goto Cleanup; 898 } 899 900 if (Level == 3 || Level > 5) 901 { 902 // The caller supplied an invalid level for EnumPrinters. 903 dwErrorCode = ERROR_INVALID_LEVEL; 904 goto Cleanup; 905 } 906 907 if (Level == 1 && Flags & PRINTER_ENUM_NAME && !Name) 908 { 909 // The caller wants information about this Print Provider. 910 // spoolss packs this into an array of information about all Print Providers. 911 dwErrorCode = _DumpLevel1PrintProviderInformation(pPrinterEnum, cbBuf, pcbNeeded, pcReturned); 912 goto Cleanup; 913 } 914 915 // Check the supplied Name parameter (if any). 916 // This may return a Computer Name string we later prepend to the output. 917 dwErrorCode = _LocalEnumPrintersCheckName(Flags, Name, wszComputerName, &cchComputerName); 918 if (dwErrorCode != ERROR_SUCCESS) 919 goto Cleanup; 920 921 // Count the required buffer size and the number of printers. 922 for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0]) 923 { 924 pPrinter = (PLOCAL_PRINTER)pNode->Element; 925 926 // TODO: If PRINTER_ENUM_SHARED is given, add this Printer if it's shared instead of just ignoring it. 927 if (Flags & PRINTER_ENUM_SHARED) 928 { 929 FIXME("Printer Sharing is not supported yet, returning no printers!\n"); 930 continue; 931 } 932 933 pfnGetPrinterLevels[Level](pPrinter, NULL, NULL, pcbNeeded, cchComputerName, wszComputerName); 934 } 935 936 // Check if the supplied buffer is large enough. 937 if (cbBuf < *pcbNeeded) 938 { 939 dwErrorCode = ERROR_INSUFFICIENT_BUFFER; 940 goto Cleanup; 941 } 942 943 // Copy over the Printer information. 944 pPrinterInfoEnd = &pPrinterEnum[*pcbNeeded]; 945 946 for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0]) 947 { 948 pPrinter = (PLOCAL_PRINTER)pNode->Element; 949 950 // TODO: If PRINTER_ENUM_SHARED is given, add this Printer if it's shared instead of just ignoring it. 951 if (Flags & PRINTER_ENUM_SHARED) 952 continue; 953 954 pfnGetPrinterLevels[Level](pPrinter, &pPrinterEnum, &pPrinterInfoEnd, NULL, cchComputerName, wszComputerName); 955 (*pcReturned)++; 956 } 957 958 dwErrorCode = ERROR_SUCCESS; 959 960 Cleanup: 961 SetLastError(dwErrorCode); 962 return (dwErrorCode == ERROR_SUCCESS); 963 } 964 965 BOOL WINAPI 966 LocalGetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded) 967 { 968 // We never prepend a Computer Name to the output, but need to provide an empty string, 969 // because this variable is passed to StringCbCopyExW. 970 const WCHAR wszDummyComputerName[] = L""; 971 972 DWORD dwErrorCode; 973 PBYTE pPrinterEnd; 974 PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter; 975 PLOCAL_PRINTER_HANDLE pPrinterHandle; 976 977 TRACE("LocalGetPrinter(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded); 978 979 // Sanity checks. 980 if (!pHandle) 981 { 982 dwErrorCode = ERROR_INVALID_HANDLE; 983 goto Cleanup; 984 } 985 986 // Check if this is a printer handle. 987 if (pHandle->HandleType != HandleType_Printer) 988 { 989 dwErrorCode = ERROR_INVALID_HANDLE; 990 goto Cleanup; 991 } 992 993 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle; 994 995 if (Level > 9) 996 { 997 // The caller supplied an invalid level for GetPrinter. 998 dwErrorCode = ERROR_INVALID_LEVEL; 999 goto Cleanup; 1000 } 1001 1002 // Count the required buffer size. 1003 *pcbNeeded = 0; 1004 pfnGetPrinterLevels[Level](pPrinterHandle->pPrinter, NULL, NULL, pcbNeeded, 0, wszDummyComputerName); 1005 1006 // Check if the supplied buffer is large enough. 1007 if (cbBuf < *pcbNeeded) 1008 { 1009 dwErrorCode = ERROR_INSUFFICIENT_BUFFER; 1010 goto Cleanup; 1011 } 1012 1013 // Copy over the Printer information. 1014 pPrinterEnd = &pPrinter[*pcbNeeded]; 1015 pfnGetPrinterLevels[Level](pPrinterHandle->pPrinter, &pPrinter, &pPrinterEnd, NULL, 0, wszDummyComputerName); 1016 dwErrorCode = ERROR_SUCCESS; 1017 1018 Cleanup: 1019 SetLastError(dwErrorCode); 1020 return (dwErrorCode == ERROR_SUCCESS); 1021 } 1022 1023 static DWORD 1024 _LocalOpenPortHandle(PWSTR pwszPortName, PHANDLE phPrinter) 1025 { 1026 BOOL bReturnValue; 1027 DWORD dwErrorCode; 1028 HANDLE hPort; 1029 PLOCAL_HANDLE pHandle = NULL; 1030 PLOCAL_PORT pPort; 1031 PLOCAL_PORT_HANDLE pPortHandle = NULL; 1032 PLOCAL_PRINT_MONITOR pPrintMonitor; 1033 1034 // Look for this port in our Print Monitor Port list. 1035 pPort = FindPort(pwszPortName); 1036 if (!pPort) 1037 { 1038 // The supplied port is unknown to all our Print Monitors. 1039 dwErrorCode = ERROR_INVALID_NAME; 1040 goto Failure; 1041 } 1042 1043 pPrintMonitor = pPort->pPrintMonitor; 1044 1045 // Call the monitor's OpenPort function. 1046 if (pPrintMonitor->bIsLevel2) 1047 bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnOpenPort(pPrintMonitor->hMonitor, pwszPortName, &hPort); 1048 else 1049 bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnOpenPort(pwszPortName, &hPort); 1050 1051 if (!bReturnValue) 1052 { 1053 // The OpenPort function failed. Return its last error. 1054 dwErrorCode = GetLastError(); 1055 goto Failure; 1056 } 1057 1058 // Create a new generic handle. 1059 pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE)); 1060 if (!pHandle) 1061 { 1062 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1063 ERR("DllAllocSplMem failed!\n"); 1064 goto Failure; 1065 } 1066 1067 // Create a new LOCAL_PORT_HANDLE. 1068 pPortHandle = DllAllocSplMem(sizeof(LOCAL_PORT_HANDLE)); 1069 if (!pPortHandle) 1070 { 1071 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1072 ERR("DllAllocSplMem failed!\n"); 1073 goto Failure; 1074 } 1075 1076 pPortHandle->hPort = hPort; 1077 pPortHandle->pPort = pPort; 1078 1079 // Make the generic handle a Port handle. 1080 pHandle->HandleType = HandleType_Port; 1081 pHandle->pSpecificHandle = pPortHandle; 1082 1083 // Return it. 1084 *phPrinter = (HANDLE)pHandle; 1085 return ERROR_SUCCESS; 1086 1087 Failure: 1088 if (pHandle) 1089 DllFreeSplMem(pHandle); 1090 1091 if (pPortHandle) 1092 DllFreeSplMem(pPortHandle); 1093 1094 return dwErrorCode; 1095 } 1096 1097 static DWORD 1098 _LocalOpenPrinterHandle(PWSTR pwszPrinterName, PWSTR pwszJobParameter, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault) 1099 { 1100 DWORD dwErrorCode; 1101 DWORD dwJobID; 1102 PLOCAL_HANDLE pHandle = NULL; 1103 PLOCAL_JOB pJob; 1104 PLOCAL_PRINTER pPrinter; 1105 PLOCAL_PRINTER_HANDLE pPrinterHandle = NULL; 1106 WCHAR wszFullPath[MAX_PATH]; 1107 1108 // Retrieve the printer from the list. 1109 pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL); 1110 if (!pPrinter) 1111 { 1112 // The printer does not exist. 1113 dwErrorCode = ERROR_INVALID_NAME; 1114 goto Failure; 1115 } 1116 1117 // Create a new generic handle. 1118 pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE)); 1119 if (!pHandle) 1120 { 1121 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1122 ERR("DllAllocSplMem failed!\n"); 1123 goto Failure; 1124 } 1125 1126 // Create a new LOCAL_PRINTER_HANDLE. 1127 pPrinterHandle = DllAllocSplMem(sizeof(LOCAL_PRINTER_HANDLE)); 1128 if (!pPrinterHandle) 1129 { 1130 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1131 ERR("DllAllocSplMem failed!\n"); 1132 goto Failure; 1133 } 1134 1135 pPrinterHandle->hSPLFile = INVALID_HANDLE_VALUE; 1136 pPrinterHandle->pPrinter = pPrinter; 1137 1138 // Check if a datatype was given. 1139 if (pDefault && pDefault->pDatatype) 1140 { 1141 // Use the datatype if it's valid. 1142 if (!FindDatatype(pPrinter->pPrintProcessor, pDefault->pDatatype)) 1143 { 1144 dwErrorCode = ERROR_INVALID_DATATYPE; 1145 goto Failure; 1146 } 1147 1148 pPrinterHandle->pwszDatatype = AllocSplStr(pDefault->pDatatype); 1149 } 1150 else 1151 { 1152 // Use the default datatype. 1153 pPrinterHandle->pwszDatatype = AllocSplStr(pPrinter->pwszDefaultDatatype); 1154 } 1155 1156 // Check if a DevMode was given, otherwise use the default. 1157 if (pDefault && pDefault->pDevMode) 1158 pPrinterHandle->pDevMode = DuplicateDevMode(pDefault->pDevMode); 1159 else 1160 pPrinterHandle->pDevMode = DuplicateDevMode(pPrinter->pDefaultDevMode); 1161 1162 // Check if the caller wants a handle to an existing Print Job. 1163 if (pwszJobParameter) 1164 { 1165 // The "Job " string has to follow now. 1166 if (wcsncmp(pwszJobParameter, L"Job ", 4) != 0) 1167 { 1168 dwErrorCode = ERROR_INVALID_NAME; 1169 goto Failure; 1170 } 1171 1172 // Skip the "Job " string. 1173 pwszJobParameter += 4; 1174 1175 // Skip even more whitespace. 1176 while (*pwszJobParameter == ' ') 1177 ++pwszJobParameter; 1178 1179 // Finally extract the desired Job ID. 1180 dwJobID = wcstoul(pwszJobParameter, NULL, 10); 1181 if (!IS_VALID_JOB_ID(dwJobID)) 1182 { 1183 // The user supplied an invalid Job ID. 1184 dwErrorCode = ERROR_INVALID_NAME; 1185 goto Failure; 1186 } 1187 1188 // Look for this job in the Global Job List. 1189 pJob = LookupElementSkiplist(&GlobalJobList, &dwJobID, NULL); 1190 if (!pJob || pJob->pPrinter != pPrinter) 1191 { 1192 // The user supplied a non-existing Job ID or the Job ID does not belong to the supplied printer name. 1193 dwErrorCode = ERROR_INVALID_PRINTER_NAME; 1194 goto Failure; 1195 } 1196 1197 // Try to open its SPL file. 1198 GetJobFilePath(L"SPL", dwJobID, wszFullPath); 1199 pPrinterHandle->hSPLFile = CreateFileW(wszFullPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); 1200 if (pPrinterHandle->hSPLFile == INVALID_HANDLE_VALUE) 1201 { 1202 dwErrorCode = GetLastError(); 1203 ERR("CreateFileW failed with error %lu for \"%S\"!", dwErrorCode, wszFullPath); 1204 goto Failure; 1205 } 1206 1207 // Associate the job to our Printer Handle, but don't set bStartedDoc. 1208 // This prevents the caller from doing further StartDocPrinter, WritePrinter, etc. calls on it. 1209 pPrinterHandle->pJob = pJob; 1210 } 1211 1212 // Make the generic handle a Printer handle. 1213 pHandle->HandleType = HandleType_Printer; 1214 pHandle->pSpecificHandle = pPrinterHandle; 1215 1216 // Return it. 1217 *phPrinter = (HANDLE)pHandle; 1218 return ERROR_SUCCESS; 1219 1220 Failure: 1221 if (pHandle) 1222 DllFreeSplMem(pHandle); 1223 1224 if (pPrinterHandle) 1225 { 1226 if (pPrinterHandle->pwszDatatype) 1227 DllFreeSplStr(pPrinterHandle->pwszDatatype); 1228 1229 if (pPrinterHandle->pDevMode) 1230 DllFreeSplMem(pPrinterHandle->pDevMode); 1231 1232 DllFreeSplMem(pPrinterHandle); 1233 } 1234 1235 return dwErrorCode; 1236 } 1237 1238 static DWORD 1239 _LocalOpenPrintServerHandle(PHANDLE phPrinter) 1240 { 1241 PLOCAL_HANDLE pHandle; 1242 1243 // Create a new generic handle. 1244 pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE)); 1245 if (!pHandle) 1246 { 1247 ERR("DllAllocSplMem failed!\n"); 1248 return ERROR_NOT_ENOUGH_MEMORY; 1249 } 1250 1251 // Make the generic handle a Print Server handle. 1252 pHandle->HandleType = HandleType_PrintServer; 1253 pHandle->pSpecificHandle = NULL; 1254 1255 // Return it. 1256 *phPrinter = (HANDLE)pHandle; 1257 return ERROR_SUCCESS; 1258 } 1259 1260 static DWORD 1261 _LocalOpenXcvHandle(PWSTR pwszParameter, PHANDLE phPrinter) 1262 { 1263 BOOL bReturnValue; 1264 DWORD dwErrorCode; 1265 HANDLE hXcv; 1266 PLOCAL_HANDLE pHandle = NULL; 1267 PLOCAL_PORT pPort; 1268 PLOCAL_PRINT_MONITOR pPrintMonitor; 1269 PLOCAL_XCV_HANDLE pXcvHandle = NULL; 1270 1271 // Skip the "Xcv" string. 1272 pwszParameter += 3; 1273 1274 // Is XcvMonitor or XcvPort requested? 1275 if (wcsncmp(pwszParameter, L"Monitor ", 8) == 0) 1276 { 1277 // Skip the "Monitor " string. 1278 pwszParameter += 8; 1279 1280 // Look for this monitor in our Print Monitor list. 1281 pPrintMonitor = FindPrintMonitor(pwszParameter); 1282 if (!pPrintMonitor) 1283 { 1284 // The caller supplied a non-existing Monitor name. 1285 dwErrorCode = ERROR_INVALID_NAME; 1286 goto Failure; 1287 } 1288 } 1289 else if (wcsncmp(pwszParameter, L"Port ", 5) == 0) 1290 { 1291 // Skip the "Port " string. 1292 pwszParameter += 5; 1293 1294 // Look for this port in our Print Monitor Port list. 1295 pPort = FindPort(pwszParameter); 1296 if (!pPort) 1297 { 1298 // The supplied port is unknown to all our Print Monitors. 1299 dwErrorCode = ERROR_INVALID_NAME; 1300 goto Failure; 1301 } 1302 1303 pPrintMonitor = pPort->pPrintMonitor; 1304 } 1305 else 1306 { 1307 dwErrorCode = ERROR_INVALID_NAME; 1308 goto Failure; 1309 } 1310 1311 // Call the monitor's XcvOpenPort function. 1312 if (pPrintMonitor->bIsLevel2) 1313 bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnXcvOpenPort(pPrintMonitor->hMonitor, pwszParameter, SERVER_EXECUTE, &hXcv); 1314 else 1315 bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnXcvOpenPort(pwszParameter, SERVER_EXECUTE, &hXcv); 1316 1317 if (!bReturnValue) 1318 { 1319 // The XcvOpenPort function failed. Return its last error. 1320 dwErrorCode = GetLastError(); 1321 goto Failure; 1322 } 1323 1324 // Create a new generic handle. 1325 pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE)); 1326 if (!pHandle) 1327 { 1328 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1329 ERR("DllAllocSplMem failed!\n"); 1330 goto Failure; 1331 } 1332 1333 // Create a new LOCAL_XCV_HANDLE. 1334 pXcvHandle = DllAllocSplMem(sizeof(LOCAL_XCV_HANDLE)); 1335 if (!pXcvHandle) 1336 { 1337 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1338 ERR("DllAllocSplMem failed!\n"); 1339 goto Failure; 1340 } 1341 1342 pXcvHandle->hXcv = hXcv; 1343 pXcvHandle->pPrintMonitor = pPrintMonitor; 1344 1345 // Make the generic handle a Xcv handle. 1346 pHandle->HandleType = HandleType_Xcv; 1347 pHandle->pSpecificHandle = pXcvHandle; 1348 1349 // Return it. 1350 *phPrinter = (HANDLE)pHandle; 1351 return ERROR_SUCCESS; 1352 1353 Failure: 1354 if (pHandle) 1355 DllFreeSplMem(pHandle); 1356 1357 if (pXcvHandle) 1358 DllFreeSplMem(pXcvHandle); 1359 1360 return dwErrorCode; 1361 } 1362 1363 BOOL WINAPI 1364 LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault) 1365 { 1366 DWORD cchComputerName; 1367 DWORD cchFirstParameter; 1368 DWORD dwErrorCode; 1369 PWSTR p = lpPrinterName; 1370 PWSTR pwszFirstParameter = NULL; 1371 PWSTR pwszSecondParameter; 1372 WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1]; 1373 1374 TRACE("LocalOpenPrinter(%S, %p, %p)\n", lpPrinterName, phPrinter, pDefault); 1375 1376 ASSERT(phPrinter); 1377 *phPrinter = NULL; 1378 1379 if (!lpPrinterName) 1380 { 1381 // The caller wants a Print Server handle and provided a NULL string. 1382 dwErrorCode = _LocalOpenPrintServerHandle(phPrinter); 1383 goto Cleanup; 1384 } 1385 1386 // Skip any server name in the first parameter. 1387 // Does lpPrinterName begin with two backslashes to indicate a server name? 1388 if (lpPrinterName[0] == L'\\' && lpPrinterName[1] == L'\\') 1389 { 1390 // Skip these two backslashes. 1391 lpPrinterName += 2; 1392 1393 // Look for the terminating null character or closing backslash. 1394 p = lpPrinterName; 1395 while (*p != L'\0' && *p != L'\\') 1396 p++; 1397 1398 // Get the local computer name for comparison. 1399 cchComputerName = _countof(wszComputerName); 1400 if (!GetComputerNameW(wszComputerName, &cchComputerName)) 1401 { 1402 dwErrorCode = GetLastError(); 1403 ERR("GetComputerNameW failed with error %lu!\n", dwErrorCode); 1404 goto Cleanup; 1405 } 1406 1407 // Now compare this string excerpt with the local computer name. 1408 // The input parameter may not be writable, so we can't null-terminate the input string at this point. 1409 // This print provider only supports local printers, so both strings have to match. 1410 if (p - lpPrinterName != cchComputerName || _wcsnicmp(lpPrinterName, wszComputerName, cchComputerName) != 0) 1411 { 1412 dwErrorCode = ERROR_INVALID_NAME; 1413 goto Cleanup; 1414 } 1415 1416 // If lpPrinterName is only "\\COMPUTERNAME" with nothing more, the caller wants a handle to the local Print Server. 1417 if (!*p) 1418 { 1419 // The caller wants a Print Server handle and provided a string like: 1420 // "\\COMPUTERNAME" 1421 dwErrorCode = _LocalOpenPrintServerHandle(phPrinter); 1422 goto Cleanup; 1423 } 1424 1425 // We have checked the server name and don't need it anymore. 1426 lpPrinterName = p + 1; 1427 } 1428 1429 // Look for a comma. If it exists, it indicates the end of the first parameter. 1430 pwszSecondParameter = wcschr(lpPrinterName, L','); 1431 if (pwszSecondParameter) 1432 cchFirstParameter = pwszSecondParameter - p; 1433 else 1434 cchFirstParameter = wcslen(lpPrinterName); 1435 1436 // We must have at least one parameter. 1437 if (!cchFirstParameter && !pwszSecondParameter) 1438 { 1439 dwErrorCode = ERROR_INVALID_NAME; 1440 goto Cleanup; 1441 } 1442 1443 // Do we have a first parameter? 1444 if (cchFirstParameter) 1445 { 1446 // Yes, extract it. 1447 // No null-termination is necessary here, because DllAllocSplMem returns a zero-initialized buffer. 1448 pwszFirstParameter = DllAllocSplMem((cchFirstParameter + 1) * sizeof(WCHAR)); 1449 CopyMemory(pwszFirstParameter, lpPrinterName, cchFirstParameter * sizeof(WCHAR)); 1450 } 1451 1452 // Do we have a second parameter? 1453 if (pwszSecondParameter) 1454 { 1455 // Yes, skip the comma at the beginning. 1456 ++pwszSecondParameter; 1457 1458 // Skip whitespace as well. 1459 while (*pwszSecondParameter == L' ') 1460 ++pwszSecondParameter; 1461 } 1462 1463 // Now we can finally check the type of handle actually requested. 1464 if (pwszFirstParameter && pwszSecondParameter && wcsncmp(pwszSecondParameter, L"Port", 4) == 0) 1465 { 1466 // The caller wants a port handle and provided a string like: 1467 // "LPT1:, Port" 1468 // "\\COMPUTERNAME\LPT1:, Port" 1469 dwErrorCode = _LocalOpenPortHandle(pwszFirstParameter, phPrinter); 1470 } 1471 else if (!pwszFirstParameter && pwszSecondParameter && wcsncmp(pwszSecondParameter, L"Xcv", 3) == 0) 1472 { 1473 // The caller wants an Xcv handle and provided a string like: 1474 // ", XcvMonitor Local Port" 1475 // "\\COMPUTERNAME\, XcvMonitor Local Port" 1476 // ", XcvPort LPT1:" 1477 // "\\COMPUTERNAME\, XcvPort LPT1:" 1478 dwErrorCode = _LocalOpenXcvHandle(pwszSecondParameter, phPrinter); 1479 } 1480 else 1481 { 1482 // The caller wants a Printer or Printer Job handle and provided a string like: 1483 // "HP DeskJet" 1484 // "\\COMPUTERNAME\HP DeskJet" 1485 // "HP DeskJet, Job 5" 1486 // "\\COMPUTERNAME\HP DeskJet, Job 5" 1487 dwErrorCode = _LocalOpenPrinterHandle(pwszFirstParameter, pwszSecondParameter, phPrinter, pDefault); 1488 } 1489 1490 Cleanup: 1491 if (pwszFirstParameter) 1492 DllFreeSplMem(pwszFirstParameter); 1493 1494 SetLastError(dwErrorCode); 1495 return (dwErrorCode == ERROR_SUCCESS); 1496 } 1497 1498 BOOL WINAPI 1499 LocalReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead) 1500 { 1501 BOOL bReturnValue; 1502 DWORD dwErrorCode; 1503 PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter; 1504 PLOCAL_PORT_HANDLE pPortHandle; 1505 PLOCAL_PRINTER_HANDLE pPrinterHandle; 1506 1507 TRACE("LocalReadPrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pNoBytesRead); 1508 1509 // Sanity checks. 1510 if (!pHandle) 1511 { 1512 dwErrorCode = ERROR_INVALID_HANDLE; 1513 goto Cleanup; 1514 } 1515 1516 // Port handles are an entirely different thing. 1517 if (pHandle->HandleType == HandleType_Port) 1518 { 1519 pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle; 1520 1521 // Call the monitor's ReadPort function. 1522 if (pPortHandle->pPort->pPrintMonitor->bIsLevel2) 1523 bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnReadPort(pPortHandle->hPort, pBuf, cbBuf, pNoBytesRead); 1524 else 1525 bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnReadPort(pPortHandle->hPort, pBuf, cbBuf, pNoBytesRead); 1526 1527 if (!bReturnValue) 1528 { 1529 // The ReadPort function failed. Return its last error. 1530 dwErrorCode = GetLastError(); 1531 goto Cleanup; 1532 } 1533 1534 // We were successful! 1535 dwErrorCode = ERROR_SUCCESS; 1536 goto Cleanup; 1537 } 1538 1539 // The remaining function deals with Printer handles only. 1540 if (pHandle->HandleType != HandleType_Printer) 1541 { 1542 dwErrorCode = ERROR_INVALID_HANDLE; 1543 goto Cleanup; 1544 } 1545 1546 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle; 1547 1548 // ReadPrinter needs an opened SPL file to work. 1549 // This only works if a Printer Job Handle was requested in OpenPrinter. 1550 if (pPrinterHandle->hSPLFile == INVALID_HANDLE_VALUE) 1551 { 1552 dwErrorCode = ERROR_INVALID_HANDLE; 1553 goto Cleanup; 1554 } 1555 1556 // Pass the parameters to ReadFile. 1557 if (!ReadFile(pPrinterHandle->hSPLFile, pBuf, cbBuf, pNoBytesRead, NULL)) 1558 { 1559 dwErrorCode = GetLastError(); 1560 ERR("ReadFile failed with error %lu!\n", dwErrorCode); 1561 goto Cleanup; 1562 } 1563 1564 dwErrorCode = ERROR_SUCCESS; 1565 1566 Cleanup: 1567 SetLastError(dwErrorCode); 1568 return (dwErrorCode == ERROR_SUCCESS); 1569 } 1570 1571 DWORD WINAPI 1572 LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo) 1573 { 1574 BOOL bReturnValue; 1575 DWORD dwErrorCode; 1576 DWORD dwReturnValue = 0; 1577 PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo; 1578 PLOCAL_JOB pJob; 1579 PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter; 1580 PLOCAL_PORT_HANDLE pPortHandle; 1581 PLOCAL_PRINTER_HANDLE pPrinterHandle; 1582 1583 TRACE("LocalStartDocPrinter(%p, %lu, %p)\n", hPrinter, Level, pDocInfo); 1584 1585 // Sanity checks. 1586 if (!pHandle) 1587 { 1588 dwErrorCode = ERROR_INVALID_HANDLE; 1589 goto Cleanup; 1590 } 1591 1592 // Port handles are an entirely different thing. 1593 if (pHandle->HandleType == HandleType_Port) 1594 { 1595 pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle; 1596 1597 // This call should come from a Print Processor and the job this port is going to print was assigned to us before opening the Print Processor. 1598 // Claim it exclusively for this port handle. 1599 pJob = pPortHandle->pPort->pNextJobToProcess; 1600 pPortHandle->pPort->pNextJobToProcess = NULL; 1601 ASSERT(pJob); 1602 1603 // Call the monitor's StartDocPort function. 1604 if (pPortHandle->pPort->pPrintMonitor->bIsLevel2) 1605 bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnStartDocPort(pPortHandle->hPort, pJob->pPrinter->pwszPrinterName, pJob->dwJobID, Level, pDocInfo); 1606 else 1607 bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnStartDocPort(pPortHandle->hPort, pJob->pPrinter->pwszPrinterName, pJob->dwJobID, Level, pDocInfo); 1608 1609 if (!bReturnValue) 1610 { 1611 // The StartDocPort function failed. Return its last error. 1612 dwErrorCode = GetLastError(); 1613 goto Cleanup; 1614 } 1615 1616 // We were successful! 1617 dwErrorCode = ERROR_SUCCESS; 1618 dwReturnValue = pJob->dwJobID; 1619 goto Cleanup; 1620 } 1621 1622 // The remaining function deals with Printer handles only. 1623 if (pHandle->HandleType != HandleType_Printer) 1624 { 1625 dwErrorCode = ERROR_INVALID_HANDLE; 1626 goto Cleanup; 1627 } 1628 1629 if (!pDocInfo1) 1630 { 1631 dwErrorCode = ERROR_INVALID_PARAMETER; 1632 goto Cleanup; 1633 } 1634 1635 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle; 1636 1637 // pJob may already be occupied if this is a Print Job handle. In this case, StartDocPrinter has to fail. 1638 if (pPrinterHandle->pJob) 1639 { 1640 dwErrorCode = ERROR_INVALID_PARAMETER; 1641 goto Cleanup; 1642 } 1643 1644 // Check the validity of the datatype if we got one. 1645 if (pDocInfo1->pDatatype && !FindDatatype(pPrinterHandle->pJob->pPrintProcessor, pDocInfo1->pDatatype)) 1646 { 1647 dwErrorCode = ERROR_INVALID_DATATYPE; 1648 goto Cleanup; 1649 } 1650 1651 // Check if this is the right document information level. 1652 if (Level != 1) 1653 { 1654 dwErrorCode = ERROR_INVALID_LEVEL; 1655 goto Cleanup; 1656 } 1657 1658 // All requirements are met - create a new job. 1659 dwErrorCode = CreateJob(pPrinterHandle); 1660 if (dwErrorCode != ERROR_SUCCESS) 1661 goto Cleanup; 1662 1663 // Use any given datatype. 1664 if (pDocInfo1->pDatatype && !ReallocSplStr(&pPrinterHandle->pJob->pwszDatatype, pDocInfo1->pDatatype)) 1665 { 1666 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1667 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError()); 1668 goto Cleanup; 1669 } 1670 1671 // Use any given document name. 1672 if (pDocInfo1->pDocName && !ReallocSplStr(&pPrinterHandle->pJob->pwszDocumentName, pDocInfo1->pDocName)) 1673 { 1674 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; 1675 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError()); 1676 goto Cleanup; 1677 } 1678 1679 // We were successful! 1680 dwErrorCode = ERROR_SUCCESS; 1681 dwReturnValue = pPrinterHandle->pJob->dwJobID; 1682 1683 Cleanup: 1684 SetLastError(dwErrorCode); 1685 return dwReturnValue; 1686 } 1687 1688 BOOL WINAPI 1689 LocalStartPagePrinter(HANDLE hPrinter) 1690 { 1691 DWORD dwErrorCode; 1692 PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter; 1693 PLOCAL_PRINTER_HANDLE pPrinterHandle; 1694 1695 TRACE("LocalStartPagePrinter(%p)\n", hPrinter); 1696 1697 // Sanity checks. 1698 if (!pHandle || pHandle->HandleType != HandleType_Printer) 1699 { 1700 dwErrorCode = ERROR_INVALID_HANDLE; 1701 goto Cleanup; 1702 } 1703 1704 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle; 1705 1706 // We require StartDocPrinter or AddJob to be called first. 1707 if (!pPrinterHandle->bStartedDoc) 1708 { 1709 dwErrorCode = ERROR_SPL_NO_STARTDOC; 1710 goto Cleanup; 1711 } 1712 1713 // Increase the page count. 1714 ++pPrinterHandle->pJob->dwTotalPages; 1715 dwErrorCode = ERROR_SUCCESS; 1716 1717 Cleanup: 1718 SetLastError(dwErrorCode); 1719 return (dwErrorCode == ERROR_SUCCESS); 1720 } 1721 1722 BOOL WINAPI 1723 LocalWritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten) 1724 { 1725 BOOL bReturnValue; 1726 DWORD dwErrorCode; 1727 PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter; 1728 PLOCAL_PORT_HANDLE pPortHandle; 1729 PLOCAL_PRINTER_HANDLE pPrinterHandle; 1730 1731 TRACE("LocalWritePrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pcWritten); 1732 1733 // Sanity checks. 1734 if (!pHandle) 1735 { 1736 dwErrorCode = ERROR_INVALID_HANDLE; 1737 goto Cleanup; 1738 } 1739 1740 // Port handles are an entirely different thing. 1741 if (pHandle->HandleType == HandleType_Port) 1742 { 1743 pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle; 1744 1745 // Call the monitor's WritePort function. 1746 if (pPortHandle->pPort->pPrintMonitor->bIsLevel2) 1747 bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnWritePort(pPortHandle->hPort, pBuf, cbBuf, pcWritten); 1748 else 1749 bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnWritePort(pPortHandle->hPort, pBuf, cbBuf, pcWritten); 1750 1751 if (!bReturnValue) 1752 { 1753 // The WritePort function failed. Return its last error. 1754 dwErrorCode = GetLastError(); 1755 goto Cleanup; 1756 } 1757 1758 // We were successful! 1759 dwErrorCode = ERROR_SUCCESS; 1760 goto Cleanup; 1761 } 1762 1763 // The remaining function deals with Printer handles only. 1764 if (pHandle->HandleType != HandleType_Printer) 1765 { 1766 dwErrorCode = ERROR_INVALID_HANDLE; 1767 goto Cleanup; 1768 } 1769 1770 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle; 1771 1772 // We require StartDocPrinter or AddJob to be called first. 1773 if (!pPrinterHandle->bStartedDoc) 1774 { 1775 dwErrorCode = ERROR_SPL_NO_STARTDOC; 1776 goto Cleanup; 1777 } 1778 1779 // TODO: This function is only called when doing non-spooled printing. 1780 // This needs to be investigated further. We can't just use pPrinterHandle->hSPLFile here, because that's currently reserved for Printer Job handles (see LocalReadPrinter). 1781 #if 0 1782 // Pass the parameters to WriteFile. 1783 if (!WriteFile(SOME_SPOOL_FILE_HANDLE, pBuf, cbBuf, pcWritten, NULL)) 1784 { 1785 dwErrorCode = GetLastError(); 1786 ERR("WriteFile failed with error %lu!\n", GetLastError()); 1787 goto Cleanup; 1788 } 1789 #endif 1790 1791 dwErrorCode = ERROR_SUCCESS; 1792 1793 Cleanup: 1794 SetLastError(dwErrorCode); 1795 return (dwErrorCode == ERROR_SUCCESS); 1796 } 1797 1798 BOOL WINAPI 1799 LocalEndPagePrinter(HANDLE hPrinter) 1800 { 1801 DWORD dwErrorCode; 1802 PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter; 1803 1804 TRACE("LocalEndPagePrinter(%p)\n", hPrinter); 1805 1806 // Sanity checks. 1807 if (!pHandle || pHandle->HandleType != HandleType_Printer) 1808 { 1809 dwErrorCode = ERROR_INVALID_HANDLE; 1810 goto Cleanup; 1811 } 1812 1813 // This function doesn't do anything else for now. 1814 dwErrorCode = ERROR_SUCCESS; 1815 1816 Cleanup: 1817 SetLastError(dwErrorCode); 1818 return (dwErrorCode == ERROR_SUCCESS); 1819 } 1820 1821 BOOL WINAPI 1822 LocalEndDocPrinter(HANDLE hPrinter) 1823 { 1824 BOOL bReturnValue; 1825 DWORD dwErrorCode; 1826 PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter; 1827 PLOCAL_PORT_HANDLE pPortHandle; 1828 PLOCAL_PRINTER_HANDLE pPrinterHandle; 1829 1830 TRACE("LocalEndDocPrinter(%p)\n", hPrinter); 1831 1832 // Sanity checks. 1833 if (!pHandle) 1834 { 1835 dwErrorCode = ERROR_INVALID_HANDLE; 1836 goto Cleanup; 1837 } 1838 1839 // Port handles are an entirely different thing. 1840 if (pHandle->HandleType == HandleType_Port) 1841 { 1842 pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle; 1843 1844 // Call the monitor's EndDocPort function. 1845 if (pPortHandle->pPort->pPrintMonitor->bIsLevel2) 1846 bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnEndDocPort(pPortHandle->hPort); 1847 else 1848 bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnEndDocPort(pPortHandle->hPort); 1849 1850 if (!bReturnValue) 1851 { 1852 // The EndDocPort function failed. Return its last error. 1853 dwErrorCode = GetLastError(); 1854 goto Cleanup; 1855 } 1856 1857 // We were successful! 1858 dwErrorCode = ERROR_SUCCESS; 1859 goto Cleanup; 1860 } 1861 1862 // The remaining function deals with Printer handles only. 1863 if (pHandle->HandleType != HandleType_Printer) 1864 { 1865 dwErrorCode = ERROR_INVALID_HANDLE; 1866 goto Cleanup; 1867 } 1868 1869 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle; 1870 1871 // We require StartDocPrinter or AddJob to be called first. 1872 if (!pPrinterHandle->bStartedDoc) 1873 { 1874 dwErrorCode = ERROR_SPL_NO_STARTDOC; 1875 goto Cleanup; 1876 } 1877 1878 // TODO: Something like ScheduleJob 1879 1880 // Finish the job. 1881 pPrinterHandle->bStartedDoc = FALSE; 1882 pPrinterHandle->pJob = NULL; 1883 dwErrorCode = ERROR_SUCCESS; 1884 1885 Cleanup: 1886 SetLastError(dwErrorCode); 1887 return (dwErrorCode == ERROR_SUCCESS); 1888 } 1889 1890 static void 1891 _LocalClosePortHandle(PLOCAL_PORT_HANDLE pPortHandle) 1892 { 1893 // Call the monitor's ClosePort function. 1894 if (pPortHandle->pPort->pPrintMonitor->bIsLevel2) 1895 ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnClosePort(pPortHandle->hPort); 1896 else 1897 ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnClosePort(pPortHandle->hPort); 1898 } 1899 1900 static void 1901 _LocalClosePrinterHandle(PLOCAL_PRINTER_HANDLE pPrinterHandle) 1902 { 1903 // Terminate any started job. 1904 if (pPrinterHandle->pJob) 1905 FreeJob(pPrinterHandle->pJob); 1906 1907 // Free memory for the fields. 1908 DllFreeSplMem(pPrinterHandle->pDevMode); 1909 DllFreeSplStr(pPrinterHandle->pwszDatatype); 1910 } 1911 1912 static void 1913 _LocalCloseXcvHandle(PLOCAL_XCV_HANDLE pXcvHandle) 1914 { 1915 // Call the monitor's XcvClosePort function. 1916 if (pXcvHandle->pPrintMonitor->bIsLevel2) 1917 ((PMONITOR2)pXcvHandle->pPrintMonitor->pMonitor)->pfnXcvClosePort(pXcvHandle->hXcv); 1918 else 1919 ((LPMONITOREX)pXcvHandle->pPrintMonitor->pMonitor)->Monitor.pfnXcvClosePort(pXcvHandle->hXcv); 1920 } 1921 1922 BOOL WINAPI 1923 LocalClosePrinter(HANDLE hPrinter) 1924 { 1925 PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter; 1926 1927 TRACE("LocalClosePrinter(%p)\n", hPrinter); 1928 1929 if (!pHandle) 1930 { 1931 SetLastError(ERROR_INVALID_HANDLE); 1932 return FALSE; 1933 } 1934 1935 if (pHandle->HandleType == HandleType_Port) 1936 { 1937 _LocalClosePortHandle(pHandle->pSpecificHandle); 1938 } 1939 else if (pHandle->HandleType == HandleType_Printer) 1940 { 1941 _LocalClosePrinterHandle(pHandle->pSpecificHandle); 1942 } 1943 else if (pHandle->HandleType == HandleType_PrintServer) 1944 { 1945 // Nothing to do. 1946 } 1947 else if (pHandle->HandleType == HandleType_Xcv) 1948 { 1949 _LocalCloseXcvHandle(pHandle->pSpecificHandle); 1950 } 1951 1952 // Free memory for the handle and the specific handle (if any). 1953 if (pHandle->pSpecificHandle) 1954 DllFreeSplMem(pHandle->pSpecificHandle); 1955 1956 DllFreeSplMem(pHandle); 1957 1958 return TRUE; 1959 } 1960