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