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
143a69fd4eSColin Finck static void _LocalGetPrinterLevel0(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_STRESS* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
153a69fd4eSColin Finck static void _LocalGetPrinterLevel1(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_1W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
163a69fd4eSColin Finck static void _LocalGetPrinterLevel2(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_2W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
173a69fd4eSColin Finck static void _LocalGetPrinterLevel3(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_3* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
183a69fd4eSColin Finck static void _LocalGetPrinterLevel4(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_4W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
193a69fd4eSColin Finck static void _LocalGetPrinterLevel5(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_5W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
203a69fd4eSColin Finck static void _LocalGetPrinterLevel6(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_6* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
213a69fd4eSColin Finck static void _LocalGetPrinterLevel7(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_7W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
223a69fd4eSColin Finck static void _LocalGetPrinterLevel8(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_8W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
233a69fd4eSColin 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
263a69fd4eSColin 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
_PrinterListCompareRoutine(PVOID FirstStruct,PVOID SecondStruct)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
96*e4930be4STimo Kreuzer 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
InitializePrinterList(VOID)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
34962c4b828SJames Tabor VOID
BroadcastChange(PLOCAL_HANDLE pHandle)35062c4b828SJames Tabor BroadcastChange(PLOCAL_HANDLE pHandle)
35162c4b828SJames Tabor {
35262c4b828SJames Tabor PLOCAL_PRINTER pPrinter;
35362c4b828SJames Tabor PSKIPLIST_NODE pNode;
35462c4b828SJames Tabor DWORD cchMachineName = 0;
35562c4b828SJames Tabor WCHAR wszMachineName[MAX_PATH] = {0}; // if not local, use Machine Name then Printer Name... pPrinter->pJob->pwszMachineName?
35662c4b828SJames Tabor
35762c4b828SJames Tabor for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
35862c4b828SJames Tabor {
35962c4b828SJames Tabor pPrinter = (PLOCAL_PRINTER)pNode->Element;
36062c4b828SJames Tabor
36162c4b828SJames Tabor StringCchCopyW( &wszMachineName[cchMachineName], sizeof(wszMachineName), pPrinter->pwszPrinterName );
36262c4b828SJames Tabor
36362c4b828SJames Tabor PostMessageW( HWND_BROADCAST, WM_DEVMODECHANGE, 0, (LPARAM)&wszMachineName );
36462c4b828SJames Tabor }
36562c4b828SJames Tabor }
36662c4b828SJames Tabor
367c2c66affSColin Finck /**
368c2c66affSColin Finck * @name _LocalEnumPrintersCheckName
369c2c66affSColin Finck *
370c2c66affSColin Finck * Checks the Name parameter supplied to a call to EnumPrinters.
371c2c66affSColin Finck *
372c2c66affSColin Finck * @param Flags
373c2c66affSColin Finck * Flags parameter of EnumPrinters.
374c2c66affSColin Finck *
375c2c66affSColin Finck * @param Name
376c2c66affSColin Finck * Name parameter of EnumPrinters to check.
377c2c66affSColin Finck *
378c2c66affSColin Finck * @param pwszComputerName
379c2c66affSColin Finck * Pointer to a string able to hold 2 + MAX_COMPUTERNAME_LENGTH + 1 + 1 characters.
380c2c66affSColin Finck * On return, it may contain a computer name to prepend in EnumPrinters depending on the case.
381c2c66affSColin Finck *
382c2c66affSColin Finck * @param pcchComputerName
383c2c66affSColin Finck * If a string to prepend is returned, this pointer receives its length in characters.
384c2c66affSColin Finck *
385c2c66affSColin Finck * @return
386c2c66affSColin Finck * ERROR_SUCCESS if processing in EnumPrinters can be continued.
387c2c66affSColin Finck * ERROR_INVALID_NAME if the Name parameter is invalid for the given flags and this Print Provider.
388c2c66affSColin Finck * Any other error code if GetComputerNameW fails. Error codes indicating failure should then be returned by EnumPrinters.
389c2c66affSColin Finck */
390c2c66affSColin Finck static DWORD
_LocalEnumPrintersCheckName(DWORD Flags,PCWSTR Name,PWSTR pwszComputerName,PDWORD pcchComputerName)391c2c66affSColin Finck _LocalEnumPrintersCheckName(DWORD Flags, PCWSTR Name, PWSTR pwszComputerName, PDWORD pcchComputerName)
392c2c66affSColin Finck {
393c2c66affSColin Finck PCWSTR pName;
394c2c66affSColin Finck PCWSTR pComputerName;
395c2c66affSColin Finck
396c2c66affSColin Finck // If there is no Name parameter to check, we can just continue in EnumPrinters.
397c2c66affSColin Finck if (!Name)
398c2c66affSColin Finck return ERROR_SUCCESS;
399c2c66affSColin Finck
400c2c66affSColin Finck // Check if Name does not begin with two backslashes (required for specifying Computer Names).
401c2c66affSColin Finck if (Name[0] != L'\\' || Name[1] != L'\\')
402c2c66affSColin Finck {
403c2c66affSColin Finck if (Flags & PRINTER_ENUM_NAME)
404c2c66affSColin Finck {
405c2c66affSColin Finck // If PRINTER_ENUM_NAME is specified, any given Name parameter may only contain the
406c2c66affSColin Finck // Print Provider Name or the local Computer Name.
407c2c66affSColin Finck
408c2c66affSColin Finck // Compare with the Print Provider Name.
409*e4930be4STimo Kreuzer if (_wcsicmp(Name, wszPrintProviderInfo[0]) == 0)
410c2c66affSColin Finck return ERROR_SUCCESS;
411c2c66affSColin Finck
412c2c66affSColin Finck // Dismiss anything else.
413c2c66affSColin Finck return ERROR_INVALID_NAME;
414c2c66affSColin Finck }
415c2c66affSColin Finck else
416c2c66affSColin Finck {
417c2c66affSColin Finck // If PRINTER_ENUM_NAME is not specified, we just ignore anything that is not a Computer Name.
418c2c66affSColin Finck return ERROR_SUCCESS;
419c2c66affSColin Finck }
420c2c66affSColin Finck }
421c2c66affSColin Finck
422c2c66affSColin Finck // Prepend the backslashes to the output computer name.
423c2c66affSColin Finck pwszComputerName[0] = L'\\';
424c2c66affSColin Finck pwszComputerName[1] = L'\\';
425c2c66affSColin Finck
426c2c66affSColin Finck // Get the local computer name for comparison.
427c2c66affSColin Finck *pcchComputerName = MAX_COMPUTERNAME_LENGTH + 1;
428c2c66affSColin Finck if (!GetComputerNameW(&pwszComputerName[2], pcchComputerName))
429c2c66affSColin Finck {
430c2c66affSColin Finck ERR("GetComputerNameW failed with error %lu!\n", GetLastError());
431c2c66affSColin Finck return GetLastError();
432c2c66affSColin Finck }
433c2c66affSColin Finck
434c2c66affSColin Finck // Add the leading slashes to the total length.
435c2c66affSColin Finck *pcchComputerName += 2;
436c2c66affSColin Finck
437c2c66affSColin Finck // Compare both names.
438c2c66affSColin Finck pComputerName = &pwszComputerName[2];
439c2c66affSColin Finck pName = &Name[2];
440c2c66affSColin Finck for (;;)
441c2c66affSColin Finck {
442c2c66affSColin Finck // Are we at the end of the local Computer Name string?
443c2c66affSColin Finck if (!*pComputerName)
444c2c66affSColin Finck {
445c2c66affSColin Finck // Are we also at the end of the supplied Name parameter?
446c2c66affSColin Finck // A terminating NUL character and a backslash are both treated as the end, but they are treated differently.
447c2c66affSColin Finck if (!*pName)
448c2c66affSColin Finck {
449c2c66affSColin Finck // If both names match and Name ends with a NUL character, the computer name will be prepended in EnumPrinters.
450c2c66affSColin Finck // Add a trailing backslash for that.
451c2c66affSColin Finck pwszComputerName[(*pcchComputerName)++] = L'\\';
452c2c66affSColin Finck pwszComputerName[*pcchComputerName] = 0;
453c2c66affSColin Finck return ERROR_SUCCESS;
454c2c66affSColin Finck }
455c2c66affSColin Finck else if (*pName == L'\\')
456c2c66affSColin Finck {
457c2c66affSColin Finck if (Flags & PRINTER_ENUM_NAME)
458c2c66affSColin Finck {
459c2c66affSColin Finck // If PRINTER_ENUM_NAME is specified and a Name parameter is given, it must be exactly the local
460c2c66affSColin Finck // Computer Name with two backslashes prepended. Anything else (like "\\COMPUTERNAME\") is dismissed.
461c2c66affSColin Finck return ERROR_INVALID_NAME;
462c2c66affSColin Finck }
463c2c66affSColin Finck else
464c2c66affSColin Finck {
465c2c66affSColin Finck // If PRINTER_ENUM_NAME is not specified and a Name parameter is given, it may also end with a backslash.
466c2c66affSColin Finck // Only the Computer Name between the backslashes is checked then.
467c2c66affSColin Finck // This is largely undocumented, but verified by tests (see winspool_apitest).
468c2c66affSColin Finck // In this case, no computer name is prepended in EnumPrinters though.
469c2c66affSColin Finck *pwszComputerName = 0;
470c2c66affSColin Finck *pcchComputerName = 0;
471c2c66affSColin Finck return ERROR_SUCCESS;
472c2c66affSColin Finck }
473c2c66affSColin Finck }
474c2c66affSColin Finck }
475c2c66affSColin Finck
476c2c66affSColin Finck // Compare both Computer Names case-insensitively and reject with ERROR_INVALID_NAME if they don't match.
477c2c66affSColin Finck if (towlower(*pName) != towlower(*pComputerName))
478c2c66affSColin Finck return ERROR_INVALID_NAME;
479c2c66affSColin Finck
480c2c66affSColin Finck pName++;
481c2c66affSColin Finck pComputerName++;
482c2c66affSColin Finck }
483c2c66affSColin Finck }
484c2c66affSColin Finck
485c2c66affSColin Finck static DWORD
_DumpLevel1PrintProviderInformation(PBYTE pPrinterEnum,DWORD cbBuf,PDWORD pcbNeeded,PDWORD pcReturned)486c2c66affSColin Finck _DumpLevel1PrintProviderInformation(PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
487c2c66affSColin Finck {
488c2c66affSColin Finck int i;
489c2c66affSColin Finck
490c2c66affSColin Finck // Count the needed bytes for Print Provider information.
491c2c66affSColin Finck *pcbNeeded = sizeof(PRINTER_INFO_1W);
492c2c66affSColin Finck
493c2c66affSColin Finck for (i = 0; i < 3; i++)
494c2c66affSColin Finck *pcbNeeded += (wcslen(wszPrintProviderInfo[i]) + 1) * sizeof(WCHAR);
495c2c66affSColin Finck
496c2c66affSColin Finck // Check if the supplied buffer is large enough.
497c2c66affSColin Finck if (cbBuf < *pcbNeeded)
498c2c66affSColin Finck return ERROR_INSUFFICIENT_BUFFER;
499c2c66affSColin Finck
500c2c66affSColin Finck // Copy over the Print Provider information.
501c2c66affSColin Finck ((PPRINTER_INFO_1W)pPrinterEnum)->Flags = 0;
502c2c66affSColin Finck PackStrings(wszPrintProviderInfo, pPrinterEnum, dwPrinterInfo1Offsets, &pPrinterEnum[*pcbNeeded]);
503c2c66affSColin Finck *pcReturned = 1;
504c2c66affSColin Finck
505c2c66affSColin Finck return ERROR_SUCCESS;
506c2c66affSColin Finck }
507c2c66affSColin Finck
508c2c66affSColin Finck static void
_LocalGetPrinterLevel0(PLOCAL_PRINTER pPrinter,PPRINTER_INFO_STRESS * ppPrinterInfo,PBYTE * ppPrinterInfoEnd,PDWORD pcbNeeded,DWORD cchComputerName,PCWSTR wszComputerName)5093a69fd4eSColin Finck _LocalGetPrinterLevel0(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_STRESS* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
510c2c66affSColin Finck {
511c2c66affSColin Finck size_t cbName;
5122e4457f2SMark Jansen PWSTR p, Allocation;
5132e4457f2SMark Jansen PCWSTR pwszStrings[1];
514c2c66affSColin Finck SYSTEM_INFO SystemInfo;
515c2c66affSColin Finck
516c2c66affSColin Finck // Calculate the string lengths.
517c2c66affSColin Finck cbName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
518c2c66affSColin Finck
519c2c66affSColin Finck if (!ppPrinterInfo)
520c2c66affSColin Finck {
521c2c66affSColin Finck *pcbNeeded += sizeof(PRINTER_INFO_STRESS) + cbName;
522c2c66affSColin Finck return;
523c2c66affSColin Finck }
524c2c66affSColin Finck
525c2c66affSColin Finck // Set the general fields.
526c2c66affSColin Finck ZeroMemory(*ppPrinterInfo, sizeof(PRINTER_INFO_STRESS));
527c2c66affSColin Finck (*ppPrinterInfo)->cJobs = pPrinter->JobList.NodeCount;
528c2c66affSColin Finck (*ppPrinterInfo)->dwGetVersion = GetVersion();
529c2c66affSColin Finck (*ppPrinterInfo)->Status = pPrinter->dwStatus;
530c2c66affSColin Finck
531b84b755eSSerge Gautherie #if !DBG
532c2c66affSColin Finck (*ppPrinterInfo)->fFreeBuild = 1;
533c2c66affSColin Finck #endif
534c2c66affSColin Finck
535c2c66affSColin Finck GetSystemInfo(&SystemInfo);
536c2c66affSColin Finck (*ppPrinterInfo)->dwNumberOfProcessors = SystemInfo.dwNumberOfProcessors;
537c2c66affSColin Finck (*ppPrinterInfo)->dwProcessorType = SystemInfo.dwProcessorType;
538c2c66affSColin Finck (*ppPrinterInfo)->wProcessorArchitecture = SystemInfo.wProcessorArchitecture;
539c2c66affSColin Finck (*ppPrinterInfo)->wProcessorLevel = SystemInfo.wProcessorLevel;
540c2c66affSColin Finck
541c2c66affSColin Finck // Copy the Printer Name.
5422e4457f2SMark Jansen p = Allocation = DllAllocSplMem(cbName);
5432e4457f2SMark Jansen pwszStrings[0] = Allocation;
544c2c66affSColin Finck StringCbCopyExW(p, cbName, wszComputerName, &p, &cbName, 0);
545c2c66affSColin Finck StringCbCopyExW(p, cbName, pPrinter->pwszPrinterName, &p, &cbName, 0);
546c2c66affSColin Finck
547c2c66affSColin Finck // Finally copy the structure and advance to the next one in the output buffer.
548c2c66affSColin Finck *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo0Offsets, *ppPrinterInfoEnd);
549c2c66affSColin Finck (*ppPrinterInfo)++;
550c2c66affSColin Finck
551c2c66affSColin Finck // Free the memory for temporary strings.
5522e4457f2SMark Jansen DllFreeSplMem(Allocation);
553c2c66affSColin Finck }
554c2c66affSColin Finck
555c2c66affSColin Finck static void
_LocalGetPrinterLevel1(PLOCAL_PRINTER pPrinter,PPRINTER_INFO_1W * ppPrinterInfo,PBYTE * ppPrinterInfoEnd,PDWORD pcbNeeded,DWORD cchComputerName,PCWSTR wszComputerName)5563a69fd4eSColin Finck _LocalGetPrinterLevel1(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_1W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
557c2c66affSColin Finck {
558c2c66affSColin Finck const WCHAR wszComma[] = L",";
559c2c66affSColin Finck
560c2c66affSColin Finck size_t cbName;
561c2c66affSColin Finck size_t cbComment;
562c2c66affSColin Finck size_t cbDescription;
5632e4457f2SMark Jansen PWSTR p, Allocation1, Allocation2;
5642e4457f2SMark Jansen PCWSTR pwszStrings[3];
565c2c66affSColin Finck
566c2c66affSColin Finck // Calculate the string lengths.
567c2c66affSColin Finck // Attention: pComment equals the "Description" registry value while pDescription is concatenated out of several strings.
568c2c66affSColin 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.
569c2c66affSColin Finck cbName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
570c2c66affSColin Finck cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR);
571c2c66affSColin Finck cbDescription = cbName + (wcslen(pPrinter->pwszPrinterDriver) + 1 + wcslen(pPrinter->pwszLocation) + 1) * sizeof(WCHAR);
572c2c66affSColin Finck
573c2c66affSColin Finck if (!ppPrinterInfo)
574c2c66affSColin Finck {
575c2c66affSColin Finck *pcbNeeded += sizeof(PRINTER_INFO_1W) + cbName + cbComment + cbDescription;
576c2c66affSColin Finck return;
577c2c66affSColin Finck }
578c2c66affSColin Finck
579c2c66affSColin Finck // Indicate that this is a Printer.
580c2c66affSColin Finck (*ppPrinterInfo)->Flags = PRINTER_ENUM_ICON8;
581c2c66affSColin Finck
582c2c66affSColin Finck // Copy the Printer Name.
5832e4457f2SMark Jansen p = Allocation1 = DllAllocSplMem(cbName);
5842e4457f2SMark Jansen pwszStrings[0] = Allocation1;
585c2c66affSColin Finck StringCbCopyExW(p, cbName, wszComputerName, &p, &cbName, 0);
586c2c66affSColin Finck StringCbCopyExW(p, cbName, pPrinter->pwszPrinterName, &p, &cbName, 0);
587c2c66affSColin Finck
588c2c66affSColin Finck // Copy the Printer comment (equals the "Description" registry value).
589c2c66affSColin Finck pwszStrings[1] = pPrinter->pwszDescription;
590c2c66affSColin Finck
591c2c66affSColin Finck // Copy the description, which for PRINTER_INFO_1W has the form "Name,Printer Driver,Location"
5922e4457f2SMark Jansen p = Allocation2 = DllAllocSplMem(cbDescription);
5932e4457f2SMark Jansen pwszStrings[2] = Allocation2;
594c2c66affSColin Finck StringCbCopyExW(p, cbDescription, wszComputerName, &p, &cbDescription, 0);
595c2c66affSColin Finck StringCbCopyExW(p, cbDescription, pPrinter->pwszPrinterName, &p, &cbDescription, 0);
596c2c66affSColin Finck StringCbCopyExW(p, cbDescription, wszComma, &p, &cbDescription, 0);
597c2c66affSColin Finck StringCbCopyExW(p, cbDescription, pPrinter->pwszPrinterDriver, &p, &cbDescription, 0);
598c2c66affSColin Finck StringCbCopyExW(p, cbDescription, wszComma, &p, &cbDescription, 0);
599c2c66affSColin Finck StringCbCopyExW(p, cbDescription, pPrinter->pwszLocation, &p, &cbDescription, 0);
600c2c66affSColin Finck
601c2c66affSColin Finck // Finally copy the structure and advance to the next one in the output buffer.
602c2c66affSColin Finck *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo1Offsets, *ppPrinterInfoEnd);
603c2c66affSColin Finck (*ppPrinterInfo)++;
604c2c66affSColin Finck
605c2c66affSColin Finck // Free the memory for temporary strings.
6062e4457f2SMark Jansen DllFreeSplMem(Allocation1);
6072e4457f2SMark Jansen DllFreeSplMem(Allocation2);
608c2c66affSColin Finck }
609c2c66affSColin Finck
610c2c66affSColin Finck static void
_LocalGetPrinterLevel2(PLOCAL_PRINTER pPrinter,PPRINTER_INFO_2W * ppPrinterInfo,PBYTE * ppPrinterInfoEnd,PDWORD pcbNeeded,DWORD cchComputerName,PCWSTR wszComputerName)6113a69fd4eSColin Finck _LocalGetPrinterLevel2(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_2W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
612c2c66affSColin Finck {
613c2c66affSColin Finck WCHAR wszEmpty[] = L"";
614c2c66affSColin Finck
615c2c66affSColin Finck size_t cbDevMode;
616c2c66affSColin Finck size_t cbPrinterName;
617c2c66affSColin Finck size_t cbShareName;
618c2c66affSColin Finck size_t cbPortName;
619c2c66affSColin Finck size_t cbDriverName;
620c2c66affSColin Finck size_t cbComment;
621c2c66affSColin Finck size_t cbLocation;
622c2c66affSColin Finck size_t cbSepFile;
623c2c66affSColin Finck size_t cbPrintProcessor;
624c2c66affSColin Finck size_t cbDatatype;
625c2c66affSColin Finck size_t cbParameters;
6262e4457f2SMark Jansen PWSTR p, Allocation;
6272e4457f2SMark Jansen PCWSTR pwszStrings[10];
62862c4b828SJames Tabor FIXME("LocalGetPrinterLevel2\n");
629c2c66affSColin Finck // Calculate the string lengths.
630c2c66affSColin Finck cbDevMode = pPrinter->pDefaultDevMode->dmSize + pPrinter->pDefaultDevMode->dmDriverExtra;
631c2c66affSColin Finck cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
632c2c66affSColin Finck
633c2c66affSColin Finck if (!ppPrinterInfo)
634c2c66affSColin Finck {
635c2c66affSColin Finck // Attention: pComment equals the "Description" registry value.
636c2c66affSColin Finck cbShareName = sizeof(wszEmpty);
637c2c66affSColin Finck cbPortName = (wcslen(pPrinter->pPort->pwszName) + 1) * sizeof(WCHAR);
638c2c66affSColin Finck cbDriverName = (wcslen(pPrinter->pwszPrinterDriver) + 1) * sizeof(WCHAR);
639c2c66affSColin Finck cbComment = (wcslen(pPrinter->pwszDescription) + 1) * sizeof(WCHAR);
640c2c66affSColin Finck cbLocation = (wcslen(pPrinter->pwszLocation) + 1) * sizeof(WCHAR);
641c2c66affSColin Finck cbSepFile = sizeof(wszEmpty);
642c2c66affSColin Finck cbPrintProcessor = (wcslen(pPrinter->pPrintProcessor->pwszName) + 1) * sizeof(WCHAR);
643c2c66affSColin Finck cbDatatype = (wcslen(pPrinter->pwszDefaultDatatype) + 1) * sizeof(WCHAR);
644c2c66affSColin Finck cbParameters = sizeof(wszEmpty);
645c2c66affSColin Finck
646c2c66affSColin Finck *pcbNeeded += sizeof(PRINTER_INFO_2W) + cbDevMode + cbPrinterName + cbShareName + cbPortName + cbDriverName + cbComment + cbLocation + cbSepFile + cbPrintProcessor + cbDatatype + cbParameters;
64762c4b828SJames Tabor FIXME("LocalGetPrinterLevel2 Needed %d\n",*pcbNeeded);
648c2c66affSColin Finck return;
649c2c66affSColin Finck }
650c2c66affSColin Finck
651c2c66affSColin Finck // Set the general fields.
652c2c66affSColin Finck ZeroMemory(*ppPrinterInfo, sizeof(PRINTER_INFO_2W));
653c2c66affSColin Finck (*ppPrinterInfo)->Attributes = pPrinter->dwAttributes;
654c2c66affSColin Finck (*ppPrinterInfo)->cJobs = pPrinter->JobList.NodeCount;
655c2c66affSColin Finck (*ppPrinterInfo)->Status = pPrinter->dwStatus;
656c2c66affSColin Finck
657c2c66affSColin Finck // Set the pDevMode field (and copy the DevMode).
658c2c66affSColin Finck *ppPrinterInfoEnd -= cbDevMode;
659c2c66affSColin Finck CopyMemory(*ppPrinterInfoEnd, pPrinter->pDefaultDevMode, cbDevMode);
660c2c66affSColin Finck (*ppPrinterInfo)->pDevMode = (PDEVMODEW)(*ppPrinterInfoEnd);
661c2c66affSColin Finck
662c2c66affSColin Finck // Set the pPrinterName field.
6632e4457f2SMark Jansen p = Allocation = DllAllocSplMem(cbPrinterName);
6642e4457f2SMark Jansen pwszStrings[0] = Allocation;
665c2c66affSColin Finck StringCbCopyExW(p, cbPrinterName, wszComputerName, &p, &cbPrinterName, 0);
666c2c66affSColin Finck StringCbCopyExW(p, cbPrinterName, pPrinter->pwszPrinterName, &p, &cbPrinterName, 0);
667c2c66affSColin Finck
668c2c66affSColin Finck // Set the pShareName field.
669c2c66affSColin Finck pwszStrings[1] = wszEmpty;
670c2c66affSColin Finck
671c2c66affSColin Finck // Set the pPortName field.
672c2c66affSColin Finck pwszStrings[2] = pPrinter->pPort->pwszName;
673c2c66affSColin Finck
674c2c66affSColin Finck // Set the pDriverName field.
675c2c66affSColin Finck pwszStrings[3] = pPrinter->pwszPrinterDriver;
676c2c66affSColin Finck
677c2c66affSColin Finck // Set the pComment field ((equals the "Description" registry value).
678c2c66affSColin Finck pwszStrings[4] = pPrinter->pwszDescription;
679c2c66affSColin Finck
680c2c66affSColin Finck // Set the pLocation field.
681c2c66affSColin Finck pwszStrings[5] = pPrinter->pwszLocation;
682c2c66affSColin Finck
683c2c66affSColin Finck // Set the pSepFile field.
684c2c66affSColin Finck pwszStrings[6] = wszEmpty;
685c2c66affSColin Finck
686c2c66affSColin Finck // Set the pPrintProcessor field.
687c2c66affSColin Finck pwszStrings[7] = pPrinter->pPrintProcessor->pwszName;
688c2c66affSColin Finck
689c2c66affSColin Finck // Set the pDatatype field.
690c2c66affSColin Finck pwszStrings[8] = pPrinter->pwszDefaultDatatype;
691c2c66affSColin Finck
692c2c66affSColin Finck // Set the pParameters field.
693c2c66affSColin Finck pwszStrings[9] = wszEmpty;
694c2c66affSColin Finck
695c2c66affSColin Finck // Finally copy the structure and advance to the next one in the output buffer.
696c2c66affSColin Finck *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo2Offsets, *ppPrinterInfoEnd);
697c2c66affSColin Finck (*ppPrinterInfo)++;
698c2c66affSColin Finck
699c2c66affSColin Finck // Free the memory for temporary strings.
7002e4457f2SMark Jansen DllFreeSplMem(Allocation);
701c2c66affSColin Finck }
702c2c66affSColin Finck
703c2c66affSColin Finck static void
_LocalGetPrinterLevel3(PLOCAL_PRINTER pPrinter,PPRINTER_INFO_3 * ppPrinterInfo,PBYTE * ppPrinterInfoEnd,PDWORD pcbNeeded,DWORD cchComputerName,PCWSTR wszComputerName)7043a69fd4eSColin Finck _LocalGetPrinterLevel3(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_3* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
705c2c66affSColin Finck {
706c2c66affSColin Finck SECURITY_DESCRIPTOR SecurityDescriptor = { 0 };
707c2c66affSColin Finck
708c2c66affSColin Finck if (!ppPrinterInfo)
709c2c66affSColin Finck {
710c2c66affSColin Finck *pcbNeeded += sizeof(PRINTER_INFO_3) + sizeof(SECURITY_DESCRIPTOR);
711c2c66affSColin Finck return;
712c2c66affSColin Finck }
713c2c66affSColin Finck
714c2c66affSColin Finck FIXME("Return a valid security descriptor for PRINTER_INFO_3\n");
715c2c66affSColin Finck
716c2c66affSColin Finck // Set the pSecurityDescriptor field (and copy the Security Descriptor).
717c2c66affSColin Finck *ppPrinterInfoEnd -= sizeof(SECURITY_DESCRIPTOR);
718c2c66affSColin Finck CopyMemory(*ppPrinterInfoEnd, &SecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
719c2c66affSColin Finck (*ppPrinterInfo)->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)(*ppPrinterInfoEnd);
720c2c66affSColin Finck
721c2c66affSColin Finck // Advance to the next structure.
722c2c66affSColin Finck (*ppPrinterInfo)++;
723c2c66affSColin Finck }
724c2c66affSColin Finck
725c2c66affSColin Finck static void
_LocalGetPrinterLevel4(PLOCAL_PRINTER pPrinter,PPRINTER_INFO_4W * ppPrinterInfo,PBYTE * ppPrinterInfoEnd,PDWORD pcbNeeded,DWORD cchComputerName,PCWSTR wszComputerName)7263a69fd4eSColin Finck _LocalGetPrinterLevel4(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_4W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
727c2c66affSColin Finck {
728c2c66affSColin Finck size_t cbPrinterName;
7292e4457f2SMark Jansen PWSTR p, Allocation;
7302e4457f2SMark Jansen PCWSTR pwszStrings[1];
731c2c66affSColin Finck
732c2c66affSColin Finck // Calculate the string lengths.
733c2c66affSColin Finck cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
734c2c66affSColin Finck
735c2c66affSColin Finck if (!ppPrinterInfo)
736c2c66affSColin Finck {
737c2c66affSColin Finck *pcbNeeded += sizeof(PRINTER_INFO_4W) + cbPrinterName;
738c2c66affSColin Finck return;
739c2c66affSColin Finck }
740c2c66affSColin Finck
741c2c66affSColin Finck // Set the general fields.
742c2c66affSColin Finck (*ppPrinterInfo)->pServerName = NULL;
743c2c66affSColin Finck (*ppPrinterInfo)->Attributes = pPrinter->dwAttributes;
744c2c66affSColin Finck
745c2c66affSColin Finck // Set the pPrinterName field.
7462e4457f2SMark Jansen p = Allocation = DllAllocSplMem(cbPrinterName);
7472e4457f2SMark Jansen pwszStrings[0] = Allocation;
748c2c66affSColin Finck StringCbCopyExW(p, cbPrinterName, wszComputerName, &p, &cbPrinterName, 0);
749c2c66affSColin Finck StringCbCopyExW(p, cbPrinterName, pPrinter->pwszPrinterName, &p, &cbPrinterName, 0);
750c2c66affSColin Finck
751c2c66affSColin Finck // Finally copy the structure and advance to the next one in the output buffer.
752c2c66affSColin Finck *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo4Offsets, *ppPrinterInfoEnd);
753c2c66affSColin Finck (*ppPrinterInfo)++;
754c2c66affSColin Finck
755c2c66affSColin Finck // Free the memory for temporary strings.
7562e4457f2SMark Jansen DllFreeSplMem(Allocation);
757c2c66affSColin Finck }
758c2c66affSColin Finck
759c2c66affSColin Finck static void
_LocalGetPrinterLevel5(PLOCAL_PRINTER pPrinter,PPRINTER_INFO_5W * ppPrinterInfo,PBYTE * ppPrinterInfoEnd,PDWORD pcbNeeded,DWORD cchComputerName,PCWSTR wszComputerName)7603a69fd4eSColin Finck _LocalGetPrinterLevel5(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_5W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
761c2c66affSColin Finck {
762c2c66affSColin Finck size_t cbPrinterName;
763c2c66affSColin Finck size_t cbPortName;
7642e4457f2SMark Jansen PWSTR p, Allocation;
7652e4457f2SMark Jansen PCWSTR pwszStrings[2];
766c2c66affSColin Finck
767c2c66affSColin Finck // Calculate the string lengths.
768c2c66affSColin Finck cbPrinterName = (cchComputerName + wcslen(pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
769c2c66affSColin Finck
770c2c66affSColin Finck if (!ppPrinterInfo)
771c2c66affSColin Finck {
772c2c66affSColin Finck cbPortName = (wcslen(pPrinter->pPort->pwszName) + 1) * sizeof(WCHAR);
773c2c66affSColin Finck
774c2c66affSColin Finck *pcbNeeded += sizeof(PRINTER_INFO_5W) + cbPrinterName + cbPortName;
775c2c66affSColin Finck return;
776c2c66affSColin Finck }
777c2c66affSColin Finck
778c2c66affSColin Finck // Set the general fields.
779c2c66affSColin Finck (*ppPrinterInfo)->Attributes = pPrinter->dwAttributes;
780c2c66affSColin Finck (*ppPrinterInfo)->DeviceNotSelectedTimeout = dwDeviceNotSelectedTimeout;
781c2c66affSColin Finck (*ppPrinterInfo)->TransmissionRetryTimeout = dwTransmissionRetryTimeout;
782c2c66affSColin Finck
783c2c66affSColin Finck // Set the pPrinterName field.
7842e4457f2SMark Jansen p = Allocation = DllAllocSplMem(cbPrinterName);
7852e4457f2SMark Jansen pwszStrings[0] = Allocation;
786c2c66affSColin Finck StringCbCopyExW(p, cbPrinterName, wszComputerName, &p, &cbPrinterName, 0);
787c2c66affSColin Finck StringCbCopyExW(p, cbPrinterName, pPrinter->pwszPrinterName, &p, &cbPrinterName, 0);
788c2c66affSColin Finck
789c2c66affSColin Finck // Set the pPortName field.
790c2c66affSColin Finck pwszStrings[1] = pPrinter->pPort->pwszName;
791c2c66affSColin Finck
792c2c66affSColin Finck // Finally copy the structure and advance to the next one in the output buffer.
793c2c66affSColin Finck *ppPrinterInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppPrinterInfo), dwPrinterInfo5Offsets, *ppPrinterInfoEnd);
794c2c66affSColin Finck (*ppPrinterInfo)++;
795c2c66affSColin Finck
796c2c66affSColin Finck // Free the memory for temporary strings.
7972e4457f2SMark Jansen DllFreeSplMem(Allocation);
798c2c66affSColin Finck }
799c2c66affSColin Finck
800c2c66affSColin Finck static void
_LocalGetPrinterLevel6(PLOCAL_PRINTER pPrinter,PPRINTER_INFO_6 * ppPrinterInfo,PBYTE * ppPrinterInfoEnd,PDWORD pcbNeeded,DWORD cchComputerName,PCWSTR wszComputerName)8013a69fd4eSColin Finck _LocalGetPrinterLevel6(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_6* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
802c2c66affSColin Finck {
803c2c66affSColin Finck if (!ppPrinterInfo)
804c2c66affSColin Finck {
805c2c66affSColin Finck *pcbNeeded += sizeof(PRINTER_INFO_6);
806c2c66affSColin Finck return;
807c2c66affSColin Finck }
808c2c66affSColin Finck
809c2c66affSColin Finck // Set the general fields.
810c2c66affSColin Finck (*ppPrinterInfo)->dwStatus = pPrinter->dwStatus;
811c2c66affSColin Finck
812c2c66affSColin Finck // Advance to the next structure.
813c2c66affSColin Finck (*ppPrinterInfo)++;
814c2c66affSColin Finck }
815c2c66affSColin Finck
816c2c66affSColin Finck static void
_LocalGetPrinterLevel7(PLOCAL_PRINTER pPrinter,PPRINTER_INFO_7W * ppPrinterInfo,PBYTE * ppPrinterInfoEnd,PDWORD pcbNeeded,DWORD cchComputerName,PCWSTR wszComputerName)8173a69fd4eSColin Finck _LocalGetPrinterLevel7(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_7W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
818c2c66affSColin Finck {
819c2c66affSColin Finck if (!ppPrinterInfo)
820c2c66affSColin Finck {
821c2c66affSColin Finck *pcbNeeded += sizeof(PRINTER_INFO_7W);
822c2c66affSColin Finck return;
823c2c66affSColin Finck }
824c2c66affSColin Finck
825c2c66affSColin Finck FIXME("No Directory Support, returning DSPRINT_UNPUBLISH for PRINTER_INFO_7 all the time!\n");
826c2c66affSColin Finck
827c2c66affSColin Finck // Set the general fields.
828c2c66affSColin Finck (*ppPrinterInfo)->dwAction = DSPRINT_UNPUBLISH;
829c2c66affSColin Finck (*ppPrinterInfo)->pszObjectGUID = NULL;
830c2c66affSColin Finck
831c2c66affSColin Finck // Advance to the next structure.
832c2c66affSColin Finck (*ppPrinterInfo)++;
833c2c66affSColin Finck }
834c2c66affSColin Finck
835c2c66affSColin Finck static void
_LocalGetPrinterLevel8(PLOCAL_PRINTER pPrinter,PPRINTER_INFO_8W * ppPrinterInfo,PBYTE * ppPrinterInfoEnd,PDWORD pcbNeeded,DWORD cchComputerName,PCWSTR wszComputerName)8363a69fd4eSColin Finck _LocalGetPrinterLevel8(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_8W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
837c2c66affSColin Finck {
838c2c66affSColin Finck DWORD cbDevMode;
839c2c66affSColin Finck
840c2c66affSColin Finck // Calculate the string lengths.
841c2c66affSColin Finck cbDevMode = pPrinter->pDefaultDevMode->dmSize + pPrinter->pDefaultDevMode->dmDriverExtra;
842c2c66affSColin Finck
843c2c66affSColin Finck if (!ppPrinterInfo)
844c2c66affSColin Finck {
845c2c66affSColin Finck *pcbNeeded += sizeof(PRINTER_INFO_8W) + cbDevMode;
846c2c66affSColin Finck return;
847c2c66affSColin Finck }
848c2c66affSColin Finck
849c2c66affSColin Finck // Set the pDevMode field (and copy the DevMode).
850c2c66affSColin Finck *ppPrinterInfoEnd -= cbDevMode;
851c2c66affSColin Finck CopyMemory(*ppPrinterInfoEnd, pPrinter->pDefaultDevMode, cbDevMode);
852c2c66affSColin Finck (*ppPrinterInfo)->pDevMode = (PDEVMODEW)(*ppPrinterInfoEnd);
853c2c66affSColin Finck
854c2c66affSColin Finck // Advance to the next structure.
855c2c66affSColin Finck (*ppPrinterInfo)++;
856c2c66affSColin Finck }
857c2c66affSColin Finck
858c2c66affSColin Finck static void
_LocalGetPrinterLevel9(PLOCAL_PRINTER pPrinter,PPRINTER_INFO_9W * ppPrinterInfo,PBYTE * ppPrinterInfoEnd,PDWORD pcbNeeded,DWORD cchComputerName,PCWSTR wszComputerName)8593a69fd4eSColin Finck _LocalGetPrinterLevel9(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_9W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
860c2c66affSColin Finck {
861c2c66affSColin Finck DWORD cbDevMode;
862c2c66affSColin Finck
863c2c66affSColin Finck // Calculate the string lengths.
864c2c66affSColin Finck cbDevMode = pPrinter->pDefaultDevMode->dmSize + pPrinter->pDefaultDevMode->dmDriverExtra;
865c2c66affSColin Finck
866c2c66affSColin Finck if (!ppPrinterInfo)
867c2c66affSColin Finck {
868c2c66affSColin Finck *pcbNeeded += sizeof(PRINTER_INFO_9W) + cbDevMode;
869c2c66affSColin Finck return;
870c2c66affSColin Finck }
871c2c66affSColin Finck
872c2c66affSColin Finck FIXME("Per-user settings are not yet implemented, returning the global DevMode for PRINTER_INFO_9!\n");
873c2c66affSColin Finck
874c2c66affSColin Finck // Set the pDevMode field (and copy the DevMode).
875c2c66affSColin Finck *ppPrinterInfoEnd -= cbDevMode;
876c2c66affSColin Finck CopyMemory(*ppPrinterInfoEnd, pPrinter->pDefaultDevMode, cbDevMode);
877c2c66affSColin Finck (*ppPrinterInfo)->pDevMode = (PDEVMODEW)(*ppPrinterInfoEnd);
878c2c66affSColin Finck
879c2c66affSColin Finck // Advance to the next structure.
880c2c66affSColin Finck (*ppPrinterInfo)++;
881c2c66affSColin Finck }
882c2c66affSColin Finck
883c2c66affSColin Finck BOOL WINAPI
LocalEnumPrinters(DWORD Flags,LPWSTR Name,DWORD Level,LPBYTE pPrinterEnum,DWORD cbBuf,LPDWORD pcbNeeded,LPDWORD pcReturned)884c2c66affSColin Finck LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
885c2c66affSColin Finck {
886c2c66affSColin Finck DWORD cchComputerName = 0;
887c2c66affSColin Finck DWORD dwErrorCode;
888c2c66affSColin Finck PBYTE pPrinterInfoEnd;
889c2c66affSColin Finck PSKIPLIST_NODE pNode;
890c2c66affSColin Finck WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1] = { 0 };
891c2c66affSColin Finck PLOCAL_PRINTER pPrinter;
892c2c66affSColin Finck
89362c4b828SJames Tabor FIXME("LocalEnumPrinters(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
894c2c66affSColin Finck
895c2c66affSColin Finck // Do no sanity checks or assertions for pcbNeeded and pcReturned here.
896c2c66affSColin Finck // This is verified and required by localspl_apitest!
897c2c66affSColin Finck
898c2c66affSColin Finck // Begin counting.
899c2c66affSColin Finck *pcbNeeded = 0;
900c2c66affSColin Finck *pcReturned = 0;
901c2c66affSColin Finck
902c2c66affSColin Finck if (Flags & PRINTER_ENUM_CONNECTIONS || Flags & PRINTER_ENUM_REMOTE || Flags & PRINTER_ENUM_NETWORK)
903c2c66affSColin Finck {
904c2c66affSColin Finck // If the flags for the Network Print Provider are given, bail out with ERROR_INVALID_NAME.
905c2c66affSColin Finck // This is the internal way for a Print Provider to signal that it doesn't handle this request.
906c2c66affSColin Finck dwErrorCode = ERROR_INVALID_NAME;
907c2c66affSColin Finck goto Cleanup;
908c2c66affSColin Finck }
909c2c66affSColin Finck
910c2c66affSColin Finck if (!(Flags & PRINTER_ENUM_LOCAL || Flags & PRINTER_ENUM_NAME))
911c2c66affSColin Finck {
912c2c66affSColin Finck // The Local Print Provider is the right destination for the request, but without any of these flags,
913c2c66affSColin Finck // there is no information that can be returned.
914c2c66affSColin Finck // So just signal a successful request.
915c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
916c2c66affSColin Finck goto Cleanup;
917c2c66affSColin Finck }
918c2c66affSColin Finck
919c2c66affSColin Finck if (Level == 3 || Level > 5)
920c2c66affSColin Finck {
921c2c66affSColin Finck // The caller supplied an invalid level for EnumPrinters.
922c2c66affSColin Finck dwErrorCode = ERROR_INVALID_LEVEL;
923c2c66affSColin Finck goto Cleanup;
924c2c66affSColin Finck }
925c2c66affSColin Finck
926c2c66affSColin Finck if (Level == 1 && Flags & PRINTER_ENUM_NAME && !Name)
927c2c66affSColin Finck {
928c2c66affSColin Finck // The caller wants information about this Print Provider.
929c2c66affSColin Finck // spoolss packs this into an array of information about all Print Providers.
930c2c66affSColin Finck dwErrorCode = _DumpLevel1PrintProviderInformation(pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
931c2c66affSColin Finck goto Cleanup;
932c2c66affSColin Finck }
933c2c66affSColin Finck
934c2c66affSColin Finck // Check the supplied Name parameter (if any).
935c2c66affSColin Finck // This may return a Computer Name string we later prepend to the output.
936c2c66affSColin Finck dwErrorCode = _LocalEnumPrintersCheckName(Flags, Name, wszComputerName, &cchComputerName);
937c2c66affSColin Finck if (dwErrorCode != ERROR_SUCCESS)
938c2c66affSColin Finck goto Cleanup;
939c2c66affSColin Finck
940c2c66affSColin Finck // Count the required buffer size and the number of printers.
941c2c66affSColin Finck for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
942c2c66affSColin Finck {
943c2c66affSColin Finck pPrinter = (PLOCAL_PRINTER)pNode->Element;
944c2c66affSColin Finck
945c2c66affSColin Finck // TODO: If PRINTER_ENUM_SHARED is given, add this Printer if it's shared instead of just ignoring it.
946c2c66affSColin Finck if (Flags & PRINTER_ENUM_SHARED)
947c2c66affSColin Finck {
948c2c66affSColin Finck FIXME("Printer Sharing is not supported yet, returning no printers!\n");
949c2c66affSColin Finck continue;
950c2c66affSColin Finck }
951c2c66affSColin Finck
952c2c66affSColin Finck pfnGetPrinterLevels[Level](pPrinter, NULL, NULL, pcbNeeded, cchComputerName, wszComputerName);
953c2c66affSColin Finck }
954c2c66affSColin Finck
955c2c66affSColin Finck // Check if the supplied buffer is large enough.
956c2c66affSColin Finck if (cbBuf < *pcbNeeded)
957c2c66affSColin Finck {
958c2c66affSColin Finck dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
959c2c66affSColin Finck goto Cleanup;
960c2c66affSColin Finck }
961c2c66affSColin Finck
962c2c66affSColin Finck // Copy over the Printer information.
963c2c66affSColin Finck pPrinterInfoEnd = &pPrinterEnum[*pcbNeeded];
964c2c66affSColin Finck
965c2c66affSColin Finck for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0])
966c2c66affSColin Finck {
967c2c66affSColin Finck pPrinter = (PLOCAL_PRINTER)pNode->Element;
968c2c66affSColin Finck
969c2c66affSColin Finck // TODO: If PRINTER_ENUM_SHARED is given, add this Printer if it's shared instead of just ignoring it.
970c2c66affSColin Finck if (Flags & PRINTER_ENUM_SHARED)
971c2c66affSColin Finck continue;
972c2c66affSColin Finck
973c2c66affSColin Finck pfnGetPrinterLevels[Level](pPrinter, &pPrinterEnum, &pPrinterInfoEnd, NULL, cchComputerName, wszComputerName);
974c2c66affSColin Finck (*pcReturned)++;
975c2c66affSColin Finck }
976c2c66affSColin Finck
977c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
978c2c66affSColin Finck
979c2c66affSColin Finck Cleanup:
980c2c66affSColin Finck SetLastError(dwErrorCode);
981c2c66affSColin Finck return (dwErrorCode == ERROR_SUCCESS);
982c2c66affSColin Finck }
983c2c66affSColin Finck
984c2c66affSColin Finck BOOL WINAPI
LocalGetPrinter(HANDLE hPrinter,DWORD Level,LPBYTE pPrinter,DWORD cbBuf,LPDWORD pcbNeeded)985c2c66affSColin Finck LocalGetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
986c2c66affSColin Finck {
9873a69fd4eSColin Finck // We never prepend a Computer Name to the output, but need to provide an empty string,
9883a69fd4eSColin Finck // because this variable is passed to StringCbCopyExW.
9893a69fd4eSColin Finck const WCHAR wszDummyComputerName[] = L"";
9903a69fd4eSColin Finck
991c2c66affSColin Finck DWORD dwErrorCode;
992c2c66affSColin Finck PBYTE pPrinterEnd;
993c2c66affSColin Finck PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
994c2c66affSColin Finck PLOCAL_PRINTER_HANDLE pPrinterHandle;
995c2c66affSColin Finck
996c2c66affSColin Finck TRACE("LocalGetPrinter(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
997c2c66affSColin Finck
998c2c66affSColin Finck // Sanity checks.
999c2c66affSColin Finck if (!pHandle)
1000c2c66affSColin Finck {
1001c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1002c2c66affSColin Finck goto Cleanup;
1003c2c66affSColin Finck }
1004c2c66affSColin Finck
1005c2c66affSColin Finck // Check if this is a printer handle.
1006c2c66affSColin Finck if (pHandle->HandleType != HandleType_Printer)
1007c2c66affSColin Finck {
1008c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1009c2c66affSColin Finck goto Cleanup;
1010c2c66affSColin Finck }
1011c2c66affSColin Finck
1012c2c66affSColin Finck pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
1013c2c66affSColin Finck
1014c2c66affSColin Finck if (Level > 9)
1015c2c66affSColin Finck {
1016c2c66affSColin Finck // The caller supplied an invalid level for GetPrinter.
1017c2c66affSColin Finck dwErrorCode = ERROR_INVALID_LEVEL;
1018c2c66affSColin Finck goto Cleanup;
1019c2c66affSColin Finck }
1020c2c66affSColin Finck
1021c2c66affSColin Finck // Count the required buffer size.
1022c2c66affSColin Finck *pcbNeeded = 0;
10233a69fd4eSColin Finck pfnGetPrinterLevels[Level](pPrinterHandle->pPrinter, NULL, NULL, pcbNeeded, 0, wszDummyComputerName);
1024c2c66affSColin Finck
1025c2c66affSColin Finck // Check if the supplied buffer is large enough.
1026c2c66affSColin Finck if (cbBuf < *pcbNeeded)
1027c2c66affSColin Finck {
1028c2c66affSColin Finck dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
1029c2c66affSColin Finck goto Cleanup;
1030c2c66affSColin Finck }
1031c2c66affSColin Finck
1032c2c66affSColin Finck // Copy over the Printer information.
1033c2c66affSColin Finck pPrinterEnd = &pPrinter[*pcbNeeded];
10343a69fd4eSColin Finck pfnGetPrinterLevels[Level](pPrinterHandle->pPrinter, &pPrinter, &pPrinterEnd, NULL, 0, wszDummyComputerName);
1035c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
1036c2c66affSColin Finck
1037c2c66affSColin Finck Cleanup:
1038c2c66affSColin Finck SetLastError(dwErrorCode);
1039c2c66affSColin Finck return (dwErrorCode == ERROR_SUCCESS);
1040c2c66affSColin Finck }
1041c2c66affSColin Finck
1042c2c66affSColin Finck static DWORD
_LocalOpenPortHandle(PWSTR pwszPortName,PHANDLE phPrinter)1043c2c66affSColin Finck _LocalOpenPortHandle(PWSTR pwszPortName, PHANDLE phPrinter)
1044c2c66affSColin Finck {
1045c2c66affSColin Finck BOOL bReturnValue;
1046c2c66affSColin Finck DWORD dwErrorCode;
1047c2c66affSColin Finck HANDLE hPort;
1048c2c66affSColin Finck PLOCAL_HANDLE pHandle = NULL;
1049c2c66affSColin Finck PLOCAL_PORT pPort;
1050c2c66affSColin Finck PLOCAL_PORT_HANDLE pPortHandle = NULL;
1051c2c66affSColin Finck PLOCAL_PRINT_MONITOR pPrintMonitor;
1052c2c66affSColin Finck
1053c2c66affSColin Finck // Look for this port in our Print Monitor Port list.
1054c2c66affSColin Finck pPort = FindPort(pwszPortName);
1055c2c66affSColin Finck if (!pPort)
1056c2c66affSColin Finck {
1057c2c66affSColin Finck // The supplied port is unknown to all our Print Monitors.
1058c2c66affSColin Finck dwErrorCode = ERROR_INVALID_NAME;
1059c2c66affSColin Finck goto Failure;
1060c2c66affSColin Finck }
1061c2c66affSColin Finck
1062c2c66affSColin Finck pPrintMonitor = pPort->pPrintMonitor;
1063c2c66affSColin Finck
1064c2c66affSColin Finck // Call the monitor's OpenPort function.
1065c2c66affSColin Finck if (pPrintMonitor->bIsLevel2)
1066c2c66affSColin Finck bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnOpenPort(pPrintMonitor->hMonitor, pwszPortName, &hPort);
1067c2c66affSColin Finck else
1068c2c66affSColin Finck bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnOpenPort(pwszPortName, &hPort);
1069c2c66affSColin Finck
1070c2c66affSColin Finck if (!bReturnValue)
1071c2c66affSColin Finck {
1072c2c66affSColin Finck // The OpenPort function failed. Return its last error.
1073c2c66affSColin Finck dwErrorCode = GetLastError();
1074c2c66affSColin Finck goto Failure;
1075c2c66affSColin Finck }
1076c2c66affSColin Finck
1077c2c66affSColin Finck // Create a new generic handle.
1078c2c66affSColin Finck pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
1079c2c66affSColin Finck if (!pHandle)
1080c2c66affSColin Finck {
1081c2c66affSColin Finck dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1082c2c66affSColin Finck ERR("DllAllocSplMem failed!\n");
1083c2c66affSColin Finck goto Failure;
1084c2c66affSColin Finck }
1085c2c66affSColin Finck
1086c2c66affSColin Finck // Create a new LOCAL_PORT_HANDLE.
1087c2c66affSColin Finck pPortHandle = DllAllocSplMem(sizeof(LOCAL_PORT_HANDLE));
1088c2c66affSColin Finck if (!pPortHandle)
1089c2c66affSColin Finck {
1090c2c66affSColin Finck dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1091c2c66affSColin Finck ERR("DllAllocSplMem failed!\n");
1092c2c66affSColin Finck goto Failure;
1093c2c66affSColin Finck }
1094c2c66affSColin Finck
1095c2c66affSColin Finck pPortHandle->hPort = hPort;
1096c2c66affSColin Finck pPortHandle->pPort = pPort;
1097c2c66affSColin Finck
1098c2c66affSColin Finck // Make the generic handle a Port handle.
1099c2c66affSColin Finck pHandle->HandleType = HandleType_Port;
1100c2c66affSColin Finck pHandle->pSpecificHandle = pPortHandle;
1101c2c66affSColin Finck
1102c2c66affSColin Finck // Return it.
1103c2c66affSColin Finck *phPrinter = (HANDLE)pHandle;
1104c2c66affSColin Finck return ERROR_SUCCESS;
1105c2c66affSColin Finck
1106c2c66affSColin Finck Failure:
1107c2c66affSColin Finck if (pHandle)
1108c2c66affSColin Finck DllFreeSplMem(pHandle);
1109c2c66affSColin Finck
1110c2c66affSColin Finck if (pPortHandle)
1111c2c66affSColin Finck DllFreeSplMem(pPortHandle);
1112c2c66affSColin Finck
1113c2c66affSColin Finck return dwErrorCode;
1114c2c66affSColin Finck }
1115c2c66affSColin Finck
1116c2c66affSColin Finck static DWORD
_LocalOpenPrinterHandle(PWSTR pwszPrinterName,PWSTR pwszJobParameter,PHANDLE phPrinter,PPRINTER_DEFAULTSW pDefault)1117c2c66affSColin Finck _LocalOpenPrinterHandle(PWSTR pwszPrinterName, PWSTR pwszJobParameter, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
1118c2c66affSColin Finck {
1119c2c66affSColin Finck DWORD dwErrorCode;
1120c2c66affSColin Finck DWORD dwJobID;
1121c2c66affSColin Finck PLOCAL_HANDLE pHandle = NULL;
1122c2c66affSColin Finck PLOCAL_JOB pJob;
1123c2c66affSColin Finck PLOCAL_PRINTER pPrinter;
1124c2c66affSColin Finck PLOCAL_PRINTER_HANDLE pPrinterHandle = NULL;
1125c2c66affSColin Finck WCHAR wszFullPath[MAX_PATH];
1126c2c66affSColin Finck
1127c2c66affSColin Finck // Retrieve the printer from the list.
1128c2c66affSColin Finck pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL);
1129c2c66affSColin Finck if (!pPrinter)
1130c2c66affSColin Finck {
1131c2c66affSColin Finck // The printer does not exist.
1132c2c66affSColin Finck dwErrorCode = ERROR_INVALID_NAME;
1133c2c66affSColin Finck goto Failure;
1134c2c66affSColin Finck }
1135c2c66affSColin Finck
1136c2c66affSColin Finck // Create a new generic handle.
1137c2c66affSColin Finck pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
1138c2c66affSColin Finck if (!pHandle)
1139c2c66affSColin Finck {
1140c2c66affSColin Finck dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1141c2c66affSColin Finck ERR("DllAllocSplMem failed!\n");
1142c2c66affSColin Finck goto Failure;
1143c2c66affSColin Finck }
1144c2c66affSColin Finck
1145c2c66affSColin Finck // Create a new LOCAL_PRINTER_HANDLE.
1146c2c66affSColin Finck pPrinterHandle = DllAllocSplMem(sizeof(LOCAL_PRINTER_HANDLE));
1147c2c66affSColin Finck if (!pPrinterHandle)
1148c2c66affSColin Finck {
1149c2c66affSColin Finck dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1150c2c66affSColin Finck ERR("DllAllocSplMem failed!\n");
1151c2c66affSColin Finck goto Failure;
1152c2c66affSColin Finck }
1153c2c66affSColin Finck
1154c2c66affSColin Finck pPrinterHandle->hSPLFile = INVALID_HANDLE_VALUE;
1155c2c66affSColin Finck pPrinterHandle->pPrinter = pPrinter;
1156c2c66affSColin Finck
1157c2c66affSColin Finck // Check if a datatype was given.
1158c2c66affSColin Finck if (pDefault && pDefault->pDatatype)
1159c2c66affSColin Finck {
1160c2c66affSColin Finck // Use the datatype if it's valid.
1161c2c66affSColin Finck if (!FindDatatype(pPrinter->pPrintProcessor, pDefault->pDatatype))
1162c2c66affSColin Finck {
1163c2c66affSColin Finck dwErrorCode = ERROR_INVALID_DATATYPE;
1164c2c66affSColin Finck goto Failure;
1165c2c66affSColin Finck }
1166c2c66affSColin Finck
1167c2c66affSColin Finck pPrinterHandle->pwszDatatype = AllocSplStr(pDefault->pDatatype);
1168c2c66affSColin Finck }
1169c2c66affSColin Finck else
1170c2c66affSColin Finck {
1171c2c66affSColin Finck // Use the default datatype.
1172c2c66affSColin Finck pPrinterHandle->pwszDatatype = AllocSplStr(pPrinter->pwszDefaultDatatype);
1173c2c66affSColin Finck }
1174c2c66affSColin Finck
1175c2c66affSColin Finck // Check if a DevMode was given, otherwise use the default.
1176c2c66affSColin Finck if (pDefault && pDefault->pDevMode)
1177c2c66affSColin Finck pPrinterHandle->pDevMode = DuplicateDevMode(pDefault->pDevMode);
1178c2c66affSColin Finck else
1179c2c66affSColin Finck pPrinterHandle->pDevMode = DuplicateDevMode(pPrinter->pDefaultDevMode);
1180c2c66affSColin Finck
1181c2c66affSColin Finck // Check if the caller wants a handle to an existing Print Job.
1182c2c66affSColin Finck if (pwszJobParameter)
1183c2c66affSColin Finck {
1184c2c66affSColin Finck // The "Job " string has to follow now.
1185c2c66affSColin Finck if (wcsncmp(pwszJobParameter, L"Job ", 4) != 0)
1186c2c66affSColin Finck {
1187c2c66affSColin Finck dwErrorCode = ERROR_INVALID_NAME;
1188c2c66affSColin Finck goto Failure;
1189c2c66affSColin Finck }
1190c2c66affSColin Finck
1191c2c66affSColin Finck // Skip the "Job " string.
1192c2c66affSColin Finck pwszJobParameter += 4;
1193c2c66affSColin Finck
1194c2c66affSColin Finck // Skip even more whitespace.
1195c2c66affSColin Finck while (*pwszJobParameter == ' ')
1196c2c66affSColin Finck ++pwszJobParameter;
1197c2c66affSColin Finck
1198c2c66affSColin Finck // Finally extract the desired Job ID.
1199c2c66affSColin Finck dwJobID = wcstoul(pwszJobParameter, NULL, 10);
1200c2c66affSColin Finck if (!IS_VALID_JOB_ID(dwJobID))
1201c2c66affSColin Finck {
1202c2c66affSColin Finck // The user supplied an invalid Job ID.
1203c2c66affSColin Finck dwErrorCode = ERROR_INVALID_NAME;
1204c2c66affSColin Finck goto Failure;
1205c2c66affSColin Finck }
1206c2c66affSColin Finck
1207c2c66affSColin Finck // Look for this job in the Global Job List.
1208c2c66affSColin Finck pJob = LookupElementSkiplist(&GlobalJobList, &dwJobID, NULL);
1209c2c66affSColin Finck if (!pJob || pJob->pPrinter != pPrinter)
1210c2c66affSColin Finck {
1211c2c66affSColin Finck // The user supplied a non-existing Job ID or the Job ID does not belong to the supplied printer name.
1212c2c66affSColin Finck dwErrorCode = ERROR_INVALID_PRINTER_NAME;
1213c2c66affSColin Finck goto Failure;
1214c2c66affSColin Finck }
1215c2c66affSColin Finck
1216c2c66affSColin Finck // Try to open its SPL file.
1217c2c66affSColin Finck GetJobFilePath(L"SPL", dwJobID, wszFullPath);
1218c2c66affSColin Finck pPrinterHandle->hSPLFile = CreateFileW(wszFullPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
1219c2c66affSColin Finck if (pPrinterHandle->hSPLFile == INVALID_HANDLE_VALUE)
1220c2c66affSColin Finck {
1221c2c66affSColin Finck dwErrorCode = GetLastError();
122203422451SSerge Gautherie ERR("CreateFileW failed with error %lu for \"%S\"!\n", dwErrorCode, wszFullPath);
1223c2c66affSColin Finck goto Failure;
1224c2c66affSColin Finck }
1225c2c66affSColin Finck
1226c2c66affSColin Finck // Associate the job to our Printer Handle, but don't set bStartedDoc.
1227c2c66affSColin Finck // This prevents the caller from doing further StartDocPrinter, WritePrinter, etc. calls on it.
1228c2c66affSColin Finck pPrinterHandle->pJob = pJob;
1229c2c66affSColin Finck }
1230c2c66affSColin Finck
1231c2c66affSColin Finck // Make the generic handle a Printer handle.
1232c2c66affSColin Finck pHandle->HandleType = HandleType_Printer;
1233c2c66affSColin Finck pHandle->pSpecificHandle = pPrinterHandle;
1234c2c66affSColin Finck
1235c2c66affSColin Finck // Return it.
1236c2c66affSColin Finck *phPrinter = (HANDLE)pHandle;
1237c2c66affSColin Finck return ERROR_SUCCESS;
1238c2c66affSColin Finck
1239c2c66affSColin Finck Failure:
1240c2c66affSColin Finck if (pHandle)
1241c2c66affSColin Finck DllFreeSplMem(pHandle);
1242c2c66affSColin Finck
1243c2c66affSColin Finck if (pPrinterHandle)
1244c2c66affSColin Finck {
1245c2c66affSColin Finck if (pPrinterHandle->pwszDatatype)
1246c2c66affSColin Finck DllFreeSplStr(pPrinterHandle->pwszDatatype);
1247c2c66affSColin Finck
1248c2c66affSColin Finck if (pPrinterHandle->pDevMode)
1249c2c66affSColin Finck DllFreeSplMem(pPrinterHandle->pDevMode);
1250c2c66affSColin Finck
1251c2c66affSColin Finck DllFreeSplMem(pPrinterHandle);
1252c2c66affSColin Finck }
1253c2c66affSColin Finck
1254c2c66affSColin Finck return dwErrorCode;
1255c2c66affSColin Finck }
1256c2c66affSColin Finck
1257c2c66affSColin Finck static DWORD
_LocalOpenPrintServerHandle(PHANDLE phPrinter)1258c2c66affSColin Finck _LocalOpenPrintServerHandle(PHANDLE phPrinter)
1259c2c66affSColin Finck {
1260c2c66affSColin Finck PLOCAL_HANDLE pHandle;
1261c2c66affSColin Finck
1262c2c66affSColin Finck // Create a new generic handle.
1263c2c66affSColin Finck pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
1264c2c66affSColin Finck if (!pHandle)
1265c2c66affSColin Finck {
1266c2c66affSColin Finck ERR("DllAllocSplMem failed!\n");
1267c2c66affSColin Finck return ERROR_NOT_ENOUGH_MEMORY;
1268c2c66affSColin Finck }
1269c2c66affSColin Finck
1270c2c66affSColin Finck // Make the generic handle a Print Server handle.
1271c2c66affSColin Finck pHandle->HandleType = HandleType_PrintServer;
1272c2c66affSColin Finck pHandle->pSpecificHandle = NULL;
1273c2c66affSColin Finck
1274c2c66affSColin Finck // Return it.
1275c2c66affSColin Finck *phPrinter = (HANDLE)pHandle;
1276c2c66affSColin Finck return ERROR_SUCCESS;
1277c2c66affSColin Finck }
1278c2c66affSColin Finck
1279c2c66affSColin Finck static DWORD
_LocalOpenXcvHandle(PWSTR pwszParameter,PHANDLE phPrinter)1280c2c66affSColin Finck _LocalOpenXcvHandle(PWSTR pwszParameter, PHANDLE phPrinter)
1281c2c66affSColin Finck {
1282c2c66affSColin Finck BOOL bReturnValue;
1283c2c66affSColin Finck DWORD dwErrorCode;
1284c2c66affSColin Finck HANDLE hXcv;
1285c2c66affSColin Finck PLOCAL_HANDLE pHandle = NULL;
1286c2c66affSColin Finck PLOCAL_PORT pPort;
1287c2c66affSColin Finck PLOCAL_PRINT_MONITOR pPrintMonitor;
1288c2c66affSColin Finck PLOCAL_XCV_HANDLE pXcvHandle = NULL;
1289c2c66affSColin Finck
1290c2c66affSColin Finck // Skip the "Xcv" string.
1291c2c66affSColin Finck pwszParameter += 3;
1292c2c66affSColin Finck
1293c2c66affSColin Finck // Is XcvMonitor or XcvPort requested?
1294c2c66affSColin Finck if (wcsncmp(pwszParameter, L"Monitor ", 8) == 0)
1295c2c66affSColin Finck {
1296c2c66affSColin Finck // Skip the "Monitor " string.
1297c2c66affSColin Finck pwszParameter += 8;
1298c2c66affSColin Finck
1299c2c66affSColin Finck // Look for this monitor in our Print Monitor list.
1300c2c66affSColin Finck pPrintMonitor = FindPrintMonitor(pwszParameter);
1301c2c66affSColin Finck if (!pPrintMonitor)
1302c2c66affSColin Finck {
1303c2c66affSColin Finck // The caller supplied a non-existing Monitor name.
1304c2c66affSColin Finck dwErrorCode = ERROR_INVALID_NAME;
130562c4b828SJames Tabor ERR("OpenXcvHandle failed on Monitor name! %lu\n", dwErrorCode);
1306c2c66affSColin Finck goto Failure;
1307c2c66affSColin Finck }
1308c2c66affSColin Finck }
1309c2c66affSColin Finck else if (wcsncmp(pwszParameter, L"Port ", 5) == 0)
1310c2c66affSColin Finck {
1311c2c66affSColin Finck // Skip the "Port " string.
1312c2c66affSColin Finck pwszParameter += 5;
1313c2c66affSColin Finck
1314c2c66affSColin Finck // Look for this port in our Print Monitor Port list.
1315c2c66affSColin Finck pPort = FindPort(pwszParameter);
1316c2c66affSColin Finck if (!pPort)
1317c2c66affSColin Finck {
1318c2c66affSColin Finck // The supplied port is unknown to all our Print Monitors.
1319c2c66affSColin Finck dwErrorCode = ERROR_INVALID_NAME;
132062c4b828SJames Tabor ERR("OpenXcvHandle failed on Port name! %lu\n", dwErrorCode);
1321c2c66affSColin Finck goto Failure;
1322c2c66affSColin Finck }
1323c2c66affSColin Finck
1324c2c66affSColin Finck pPrintMonitor = pPort->pPrintMonitor;
1325c2c66affSColin Finck }
1326c2c66affSColin Finck else
1327c2c66affSColin Finck {
1328c2c66affSColin Finck dwErrorCode = ERROR_INVALID_NAME;
132962c4b828SJames Tabor ERR("OpenXcvHandle failed on bad name! %lu\n", dwErrorCode);
1330c2c66affSColin Finck goto Failure;
1331c2c66affSColin Finck }
1332c2c66affSColin Finck
1333c2c66affSColin Finck // Call the monitor's XcvOpenPort function.
1334c2c66affSColin Finck if (pPrintMonitor->bIsLevel2)
1335c2c66affSColin Finck bReturnValue = ((PMONITOR2)pPrintMonitor->pMonitor)->pfnXcvOpenPort(pPrintMonitor->hMonitor, pwszParameter, SERVER_EXECUTE, &hXcv);
1336c2c66affSColin Finck else
1337c2c66affSColin Finck bReturnValue = ((LPMONITOREX)pPrintMonitor->pMonitor)->Monitor.pfnXcvOpenPort(pwszParameter, SERVER_EXECUTE, &hXcv);
1338c2c66affSColin Finck
1339c2c66affSColin Finck if (!bReturnValue)
1340c2c66affSColin Finck {
1341c2c66affSColin Finck // The XcvOpenPort function failed. Return its last error.
1342c2c66affSColin Finck dwErrorCode = GetLastError();
134362c4b828SJames Tabor ERR("XcvOpenPort function failed! %lu\n", dwErrorCode);
1344c2c66affSColin Finck goto Failure;
1345c2c66affSColin Finck }
1346c2c66affSColin Finck
1347c2c66affSColin Finck // Create a new generic handle.
1348c2c66affSColin Finck pHandle = DllAllocSplMem(sizeof(LOCAL_HANDLE));
1349c2c66affSColin Finck if (!pHandle)
1350c2c66affSColin Finck {
1351c2c66affSColin Finck dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1352c2c66affSColin Finck ERR("DllAllocSplMem failed!\n");
1353c2c66affSColin Finck goto Failure;
1354c2c66affSColin Finck }
1355c2c66affSColin Finck
1356c2c66affSColin Finck // Create a new LOCAL_XCV_HANDLE.
1357c2c66affSColin Finck pXcvHandle = DllAllocSplMem(sizeof(LOCAL_XCV_HANDLE));
1358c2c66affSColin Finck if (!pXcvHandle)
1359c2c66affSColin Finck {
1360c2c66affSColin Finck dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1361c2c66affSColin Finck ERR("DllAllocSplMem failed!\n");
1362c2c66affSColin Finck goto Failure;
1363c2c66affSColin Finck }
1364c2c66affSColin Finck
1365c2c66affSColin Finck pXcvHandle->hXcv = hXcv;
1366c2c66affSColin Finck pXcvHandle->pPrintMonitor = pPrintMonitor;
1367c2c66affSColin Finck
1368c2c66affSColin Finck // Make the generic handle a Xcv handle.
1369c2c66affSColin Finck pHandle->HandleType = HandleType_Xcv;
1370c2c66affSColin Finck pHandle->pSpecificHandle = pXcvHandle;
1371c2c66affSColin Finck
1372c2c66affSColin Finck // Return it.
1373c2c66affSColin Finck *phPrinter = (HANDLE)pHandle;
137462c4b828SJames Tabor ERR("OpenXcvHandle Success! %p\n", pXcvHandle);
1375c2c66affSColin Finck return ERROR_SUCCESS;
1376c2c66affSColin Finck
1377c2c66affSColin Finck Failure:
1378c2c66affSColin Finck if (pHandle)
1379c2c66affSColin Finck DllFreeSplMem(pHandle);
1380c2c66affSColin Finck
1381c2c66affSColin Finck if (pXcvHandle)
1382c2c66affSColin Finck DllFreeSplMem(pXcvHandle);
1383c2c66affSColin Finck
1384c2c66affSColin Finck return dwErrorCode;
1385c2c66affSColin Finck }
1386c2c66affSColin Finck
138762c4b828SJames Tabor //
138862c4b828SJames Tabor // Dead API
138962c4b828SJames Tabor //
139062c4b828SJames Tabor DWORD WINAPI
LocalPrinterMessageBox(HANDLE hPrinter,DWORD Error,HWND hWnd,LPWSTR pText,LPWSTR pCaption,DWORD dwType)139162c4b828SJames Tabor LocalPrinterMessageBox(HANDLE hPrinter, DWORD Error, HWND hWnd, LPWSTR pText, LPWSTR pCaption, DWORD dwType)
139262c4b828SJames Tabor {
139362c4b828SJames Tabor SetLastError(ERROR_INVALID_HANDLE); // Yes....
139462c4b828SJames Tabor return 0;
139562c4b828SJames Tabor }
139662c4b828SJames Tabor
1397c2c66affSColin Finck BOOL WINAPI
LocalOpenPrinter(PWSTR lpPrinterName,HANDLE * phPrinter,PPRINTER_DEFAULTSW pDefault)1398c2c66affSColin Finck LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault)
1399c2c66affSColin Finck {
1400c2c66affSColin Finck DWORD cchComputerName;
1401c2c66affSColin Finck DWORD cchFirstParameter;
1402c2c66affSColin Finck DWORD dwErrorCode;
1403c2c66affSColin Finck PWSTR p = lpPrinterName;
1404c2c66affSColin Finck PWSTR pwszFirstParameter = NULL;
1405c2c66affSColin Finck PWSTR pwszSecondParameter;
1406c2c66affSColin Finck WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1];
1407c2c66affSColin Finck
1408c2c66affSColin Finck TRACE("LocalOpenPrinter(%S, %p, %p)\n", lpPrinterName, phPrinter, pDefault);
1409c2c66affSColin Finck
1410c2c66affSColin Finck ASSERT(phPrinter);
1411c2c66affSColin Finck *phPrinter = NULL;
1412c2c66affSColin Finck
1413c2c66affSColin Finck if (!lpPrinterName)
1414c2c66affSColin Finck {
1415c2c66affSColin Finck // The caller wants a Print Server handle and provided a NULL string.
1416c2c66affSColin Finck dwErrorCode = _LocalOpenPrintServerHandle(phPrinter);
1417c2c66affSColin Finck goto Cleanup;
1418c2c66affSColin Finck }
1419c2c66affSColin Finck
1420c2c66affSColin Finck // Skip any server name in the first parameter.
1421c2c66affSColin Finck // Does lpPrinterName begin with two backslashes to indicate a server name?
1422c2c66affSColin Finck if (lpPrinterName[0] == L'\\' && lpPrinterName[1] == L'\\')
1423c2c66affSColin Finck {
1424c2c66affSColin Finck // Skip these two backslashes.
1425c2c66affSColin Finck lpPrinterName += 2;
1426c2c66affSColin Finck
1427c2c66affSColin Finck // Look for the terminating null character or closing backslash.
1428c2c66affSColin Finck p = lpPrinterName;
1429c2c66affSColin Finck while (*p != L'\0' && *p != L'\\')
1430c2c66affSColin Finck p++;
1431c2c66affSColin Finck
1432c2c66affSColin Finck // Get the local computer name for comparison.
1433c2c66affSColin Finck cchComputerName = _countof(wszComputerName);
1434c2c66affSColin Finck if (!GetComputerNameW(wszComputerName, &cchComputerName))
1435c2c66affSColin Finck {
1436c2c66affSColin Finck dwErrorCode = GetLastError();
1437c2c66affSColin Finck ERR("GetComputerNameW failed with error %lu!\n", dwErrorCode);
1438c2c66affSColin Finck goto Cleanup;
1439c2c66affSColin Finck }
1440c2c66affSColin Finck
1441c2c66affSColin Finck // Now compare this string excerpt with the local computer name.
1442c2c66affSColin Finck // The input parameter may not be writable, so we can't null-terminate the input string at this point.
1443c2c66affSColin Finck // This print provider only supports local printers, so both strings have to match.
1444c2c66affSColin Finck if (p - lpPrinterName != cchComputerName || _wcsnicmp(lpPrinterName, wszComputerName, cchComputerName) != 0)
1445c2c66affSColin Finck {
1446c2c66affSColin Finck dwErrorCode = ERROR_INVALID_NAME;
1447c2c66affSColin Finck goto Cleanup;
1448c2c66affSColin Finck }
1449c2c66affSColin Finck
1450c2c66affSColin Finck // If lpPrinterName is only "\\COMPUTERNAME" with nothing more, the caller wants a handle to the local Print Server.
1451c2c66affSColin Finck if (!*p)
1452c2c66affSColin Finck {
1453c2c66affSColin Finck // The caller wants a Print Server handle and provided a string like:
1454c2c66affSColin Finck // "\\COMPUTERNAME"
1455c2c66affSColin Finck dwErrorCode = _LocalOpenPrintServerHandle(phPrinter);
1456c2c66affSColin Finck goto Cleanup;
1457c2c66affSColin Finck }
1458c2c66affSColin Finck
1459c2c66affSColin Finck // We have checked the server name and don't need it anymore.
1460c2c66affSColin Finck lpPrinterName = p + 1;
1461c2c66affSColin Finck }
1462c2c66affSColin Finck
1463c2c66affSColin Finck // Look for a comma. If it exists, it indicates the end of the first parameter.
1464c2c66affSColin Finck pwszSecondParameter = wcschr(lpPrinterName, L',');
1465c2c66affSColin Finck if (pwszSecondParameter)
1466c2c66affSColin Finck cchFirstParameter = pwszSecondParameter - p;
1467c2c66affSColin Finck else
1468c2c66affSColin Finck cchFirstParameter = wcslen(lpPrinterName);
1469c2c66affSColin Finck
1470c2c66affSColin Finck // We must have at least one parameter.
1471c2c66affSColin Finck if (!cchFirstParameter && !pwszSecondParameter)
1472c2c66affSColin Finck {
1473c2c66affSColin Finck dwErrorCode = ERROR_INVALID_NAME;
1474c2c66affSColin Finck goto Cleanup;
1475c2c66affSColin Finck }
1476c2c66affSColin Finck
1477c2c66affSColin Finck // Do we have a first parameter?
1478c2c66affSColin Finck if (cchFirstParameter)
1479c2c66affSColin Finck {
1480c2c66affSColin Finck // Yes, extract it.
1481c2c66affSColin Finck // No null-termination is necessary here, because DllAllocSplMem returns a zero-initialized buffer.
1482c2c66affSColin Finck pwszFirstParameter = DllAllocSplMem((cchFirstParameter + 1) * sizeof(WCHAR));
1483c2c66affSColin Finck CopyMemory(pwszFirstParameter, lpPrinterName, cchFirstParameter * sizeof(WCHAR));
1484c2c66affSColin Finck }
1485c2c66affSColin Finck
1486c2c66affSColin Finck // Do we have a second parameter?
1487c2c66affSColin Finck if (pwszSecondParameter)
1488c2c66affSColin Finck {
1489c2c66affSColin Finck // Yes, skip the comma at the beginning.
1490c2c66affSColin Finck ++pwszSecondParameter;
1491c2c66affSColin Finck
1492c2c66affSColin Finck // Skip whitespace as well.
1493c2c66affSColin Finck while (*pwszSecondParameter == L' ')
1494c2c66affSColin Finck ++pwszSecondParameter;
1495c2c66affSColin Finck }
1496c2c66affSColin Finck
1497c2c66affSColin Finck // Now we can finally check the type of handle actually requested.
1498c2c66affSColin Finck if (pwszFirstParameter && pwszSecondParameter && wcsncmp(pwszSecondParameter, L"Port", 4) == 0)
1499c2c66affSColin Finck {
1500c2c66affSColin Finck // The caller wants a port handle and provided a string like:
1501c2c66affSColin Finck // "LPT1:, Port"
1502c2c66affSColin Finck // "\\COMPUTERNAME\LPT1:, Port"
1503c2c66affSColin Finck dwErrorCode = _LocalOpenPortHandle(pwszFirstParameter, phPrinter);
1504c2c66affSColin Finck }
1505c2c66affSColin Finck else if (!pwszFirstParameter && pwszSecondParameter && wcsncmp(pwszSecondParameter, L"Xcv", 3) == 0)
1506c2c66affSColin Finck {
1507c2c66affSColin Finck // The caller wants an Xcv handle and provided a string like:
1508c2c66affSColin Finck // ", XcvMonitor Local Port"
1509c2c66affSColin Finck // "\\COMPUTERNAME\, XcvMonitor Local Port"
1510c2c66affSColin Finck // ", XcvPort LPT1:"
1511c2c66affSColin Finck // "\\COMPUTERNAME\, XcvPort LPT1:"
151262c4b828SJames Tabor FIXME("OpenXcvHandle : %S\n",pwszSecondParameter);
1513c2c66affSColin Finck dwErrorCode = _LocalOpenXcvHandle(pwszSecondParameter, phPrinter);
1514c2c66affSColin Finck }
1515c2c66affSColin Finck else
1516c2c66affSColin Finck {
1517c2c66affSColin Finck // The caller wants a Printer or Printer Job handle and provided a string like:
1518c2c66affSColin Finck // "HP DeskJet"
1519c2c66affSColin Finck // "\\COMPUTERNAME\HP DeskJet"
1520c2c66affSColin Finck // "HP DeskJet, Job 5"
1521c2c66affSColin Finck // "\\COMPUTERNAME\HP DeskJet, Job 5"
1522c2c66affSColin Finck dwErrorCode = _LocalOpenPrinterHandle(pwszFirstParameter, pwszSecondParameter, phPrinter, pDefault);
1523c2c66affSColin Finck }
1524c2c66affSColin Finck
1525c2c66affSColin Finck Cleanup:
1526c2c66affSColin Finck if (pwszFirstParameter)
1527c2c66affSColin Finck DllFreeSplMem(pwszFirstParameter);
1528c2c66affSColin Finck
1529c2c66affSColin Finck SetLastError(dwErrorCode);
1530c2c66affSColin Finck return (dwErrorCode == ERROR_SUCCESS);
1531c2c66affSColin Finck }
1532c2c66affSColin Finck
1533c2c66affSColin Finck BOOL WINAPI
LocalReadPrinter(HANDLE hPrinter,PVOID pBuf,DWORD cbBuf,PDWORD pNoBytesRead)1534c2c66affSColin Finck LocalReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
1535c2c66affSColin Finck {
1536c2c66affSColin Finck BOOL bReturnValue;
1537c2c66affSColin Finck DWORD dwErrorCode;
1538c2c66affSColin Finck PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
1539c2c66affSColin Finck PLOCAL_PORT_HANDLE pPortHandle;
1540c2c66affSColin Finck PLOCAL_PRINTER_HANDLE pPrinterHandle;
1541c2c66affSColin Finck
1542c2c66affSColin Finck TRACE("LocalReadPrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pNoBytesRead);
1543c2c66affSColin Finck
1544c2c66affSColin Finck // Sanity checks.
1545c2c66affSColin Finck if (!pHandle)
1546c2c66affSColin Finck {
1547c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1548c2c66affSColin Finck goto Cleanup;
1549c2c66affSColin Finck }
1550c2c66affSColin Finck
1551c2c66affSColin Finck // Port handles are an entirely different thing.
1552c2c66affSColin Finck if (pHandle->HandleType == HandleType_Port)
1553c2c66affSColin Finck {
1554c2c66affSColin Finck pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle;
1555c2c66affSColin Finck
1556c2c66affSColin Finck // Call the monitor's ReadPort function.
1557c2c66affSColin Finck if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
1558c2c66affSColin Finck bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnReadPort(pPortHandle->hPort, pBuf, cbBuf, pNoBytesRead);
1559c2c66affSColin Finck else
1560c2c66affSColin Finck bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnReadPort(pPortHandle->hPort, pBuf, cbBuf, pNoBytesRead);
1561c2c66affSColin Finck
1562c2c66affSColin Finck if (!bReturnValue)
1563c2c66affSColin Finck {
1564c2c66affSColin Finck // The ReadPort function failed. Return its last error.
1565c2c66affSColin Finck dwErrorCode = GetLastError();
1566c2c66affSColin Finck goto Cleanup;
1567c2c66affSColin Finck }
1568c2c66affSColin Finck
1569c2c66affSColin Finck // We were successful!
1570c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
1571c2c66affSColin Finck goto Cleanup;
1572c2c66affSColin Finck }
1573c2c66affSColin Finck
1574c2c66affSColin Finck // The remaining function deals with Printer handles only.
1575c2c66affSColin Finck if (pHandle->HandleType != HandleType_Printer)
1576c2c66affSColin Finck {
1577c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1578c2c66affSColin Finck goto Cleanup;
1579c2c66affSColin Finck }
1580c2c66affSColin Finck
1581c2c66affSColin Finck pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
1582c2c66affSColin Finck
1583c2c66affSColin Finck // ReadPrinter needs an opened SPL file to work.
1584c2c66affSColin Finck // This only works if a Printer Job Handle was requested in OpenPrinter.
1585c2c66affSColin Finck if (pPrinterHandle->hSPLFile == INVALID_HANDLE_VALUE)
1586c2c66affSColin Finck {
1587c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1588c2c66affSColin Finck goto Cleanup;
1589c2c66affSColin Finck }
1590c2c66affSColin Finck
1591c2c66affSColin Finck // Pass the parameters to ReadFile.
1592c2c66affSColin Finck if (!ReadFile(pPrinterHandle->hSPLFile, pBuf, cbBuf, pNoBytesRead, NULL))
1593c2c66affSColin Finck {
1594c2c66affSColin Finck dwErrorCode = GetLastError();
1595c2c66affSColin Finck ERR("ReadFile failed with error %lu!\n", dwErrorCode);
1596c2c66affSColin Finck goto Cleanup;
1597c2c66affSColin Finck }
1598c2c66affSColin Finck
1599c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
1600c2c66affSColin Finck
1601c2c66affSColin Finck Cleanup:
1602c2c66affSColin Finck SetLastError(dwErrorCode);
1603c2c66affSColin Finck return (dwErrorCode == ERROR_SUCCESS);
1604c2c66affSColin Finck }
1605c2c66affSColin Finck
1606c2c66affSColin Finck DWORD WINAPI
LocalStartDocPrinter(HANDLE hPrinter,DWORD Level,PBYTE pDocInfo)1607c2c66affSColin Finck LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
1608c2c66affSColin Finck {
1609c2c66affSColin Finck BOOL bReturnValue;
1610c2c66affSColin Finck DWORD dwErrorCode;
1611c2c66affSColin Finck DWORD dwReturnValue = 0;
1612c2c66affSColin Finck PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
1613c2c66affSColin Finck PLOCAL_JOB pJob;
1614c2c66affSColin Finck PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
1615c2c66affSColin Finck PLOCAL_PORT_HANDLE pPortHandle;
1616c2c66affSColin Finck PLOCAL_PRINTER_HANDLE pPrinterHandle;
1617c2c66affSColin Finck
1618c2c66affSColin Finck TRACE("LocalStartDocPrinter(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
1619c2c66affSColin Finck
1620c2c66affSColin Finck // Sanity checks.
1621c2c66affSColin Finck if (!pHandle)
1622c2c66affSColin Finck {
1623c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1624c2c66affSColin Finck goto Cleanup;
1625c2c66affSColin Finck }
1626c2c66affSColin Finck
1627c2c66affSColin Finck // Port handles are an entirely different thing.
1628c2c66affSColin Finck if (pHandle->HandleType == HandleType_Port)
1629c2c66affSColin Finck {
1630c2c66affSColin Finck pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle;
1631c2c66affSColin Finck
1632c2c66affSColin 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.
1633c2c66affSColin Finck // Claim it exclusively for this port handle.
1634c2c66affSColin Finck pJob = pPortHandle->pPort->pNextJobToProcess;
1635c2c66affSColin Finck pPortHandle->pPort->pNextJobToProcess = NULL;
1636c2c66affSColin Finck ASSERT(pJob);
1637c2c66affSColin Finck
1638c2c66affSColin Finck // Call the monitor's StartDocPort function.
1639c2c66affSColin Finck if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
1640c2c66affSColin Finck bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnStartDocPort(pPortHandle->hPort, pJob->pPrinter->pwszPrinterName, pJob->dwJobID, Level, pDocInfo);
1641c2c66affSColin Finck else
1642c2c66affSColin Finck bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnStartDocPort(pPortHandle->hPort, pJob->pPrinter->pwszPrinterName, pJob->dwJobID, Level, pDocInfo);
1643c2c66affSColin Finck
1644c2c66affSColin Finck if (!bReturnValue)
1645c2c66affSColin Finck {
1646c2c66affSColin Finck // The StartDocPort function failed. Return its last error.
1647c2c66affSColin Finck dwErrorCode = GetLastError();
1648c2c66affSColin Finck goto Cleanup;
1649c2c66affSColin Finck }
1650c2c66affSColin Finck
1651c2c66affSColin Finck // We were successful!
1652c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
1653c2c66affSColin Finck dwReturnValue = pJob->dwJobID;
1654c2c66affSColin Finck goto Cleanup;
1655c2c66affSColin Finck }
1656c2c66affSColin Finck
1657c2c66affSColin Finck // The remaining function deals with Printer handles only.
1658c2c66affSColin Finck if (pHandle->HandleType != HandleType_Printer)
1659c2c66affSColin Finck {
1660c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1661c2c66affSColin Finck goto Cleanup;
1662c2c66affSColin Finck }
1663c2c66affSColin Finck
1664c2c66affSColin Finck if (!pDocInfo1)
1665c2c66affSColin Finck {
1666c2c66affSColin Finck dwErrorCode = ERROR_INVALID_PARAMETER;
1667c2c66affSColin Finck goto Cleanup;
1668c2c66affSColin Finck }
1669c2c66affSColin Finck
1670c2c66affSColin Finck pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
1671c2c66affSColin Finck
1672c2c66affSColin Finck // pJob may already be occupied if this is a Print Job handle. In this case, StartDocPrinter has to fail.
1673c2c66affSColin Finck if (pPrinterHandle->pJob)
1674c2c66affSColin Finck {
1675c2c66affSColin Finck dwErrorCode = ERROR_INVALID_PARAMETER;
1676c2c66affSColin Finck goto Cleanup;
1677c2c66affSColin Finck }
1678c2c66affSColin Finck
1679c2c66affSColin Finck // Check the validity of the datatype if we got one.
1680c2c66affSColin Finck if (pDocInfo1->pDatatype && !FindDatatype(pPrinterHandle->pJob->pPrintProcessor, pDocInfo1->pDatatype))
1681c2c66affSColin Finck {
1682c2c66affSColin Finck dwErrorCode = ERROR_INVALID_DATATYPE;
1683c2c66affSColin Finck goto Cleanup;
1684c2c66affSColin Finck }
1685c2c66affSColin Finck
1686c2c66affSColin Finck // Check if this is the right document information level.
1687c2c66affSColin Finck if (Level != 1)
1688c2c66affSColin Finck {
1689c2c66affSColin Finck dwErrorCode = ERROR_INVALID_LEVEL;
1690c2c66affSColin Finck goto Cleanup;
1691c2c66affSColin Finck }
1692c2c66affSColin Finck
1693c2c66affSColin Finck // All requirements are met - create a new job.
1694c2c66affSColin Finck dwErrorCode = CreateJob(pPrinterHandle);
1695c2c66affSColin Finck if (dwErrorCode != ERROR_SUCCESS)
1696c2c66affSColin Finck goto Cleanup;
1697c2c66affSColin Finck
1698c2c66affSColin Finck // Use any given datatype.
1699c2c66affSColin Finck if (pDocInfo1->pDatatype && !ReallocSplStr(&pPrinterHandle->pJob->pwszDatatype, pDocInfo1->pDatatype))
1700c2c66affSColin Finck {
1701c2c66affSColin Finck dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1702c2c66affSColin Finck ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
1703c2c66affSColin Finck goto Cleanup;
1704c2c66affSColin Finck }
1705c2c66affSColin Finck
1706c2c66affSColin Finck // Use any given document name.
1707c2c66affSColin Finck if (pDocInfo1->pDocName && !ReallocSplStr(&pPrinterHandle->pJob->pwszDocumentName, pDocInfo1->pDocName))
1708c2c66affSColin Finck {
1709c2c66affSColin Finck dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1710c2c66affSColin Finck ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
1711c2c66affSColin Finck goto Cleanup;
1712c2c66affSColin Finck }
1713c2c66affSColin Finck
1714c2c66affSColin Finck // We were successful!
1715c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
1716c2c66affSColin Finck dwReturnValue = pPrinterHandle->pJob->dwJobID;
1717c2c66affSColin Finck
1718c2c66affSColin Finck Cleanup:
1719c2c66affSColin Finck SetLastError(dwErrorCode);
1720c2c66affSColin Finck return dwReturnValue;
1721c2c66affSColin Finck }
1722c2c66affSColin Finck
1723c2c66affSColin Finck BOOL WINAPI
LocalStartPagePrinter(HANDLE hPrinter)1724c2c66affSColin Finck LocalStartPagePrinter(HANDLE hPrinter)
1725c2c66affSColin Finck {
1726c2c66affSColin Finck DWORD dwErrorCode;
1727c2c66affSColin Finck PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
1728c2c66affSColin Finck PLOCAL_PRINTER_HANDLE pPrinterHandle;
1729c2c66affSColin Finck
1730c2c66affSColin Finck TRACE("LocalStartPagePrinter(%p)\n", hPrinter);
1731c2c66affSColin Finck
1732c2c66affSColin Finck // Sanity checks.
1733c2c66affSColin Finck if (!pHandle || pHandle->HandleType != HandleType_Printer)
1734c2c66affSColin Finck {
1735c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1736c2c66affSColin Finck goto Cleanup;
1737c2c66affSColin Finck }
1738c2c66affSColin Finck
1739c2c66affSColin Finck pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
1740c2c66affSColin Finck
1741c2c66affSColin Finck // We require StartDocPrinter or AddJob to be called first.
1742c2c66affSColin Finck if (!pPrinterHandle->bStartedDoc)
1743c2c66affSColin Finck {
1744c2c66affSColin Finck dwErrorCode = ERROR_SPL_NO_STARTDOC;
1745c2c66affSColin Finck goto Cleanup;
1746c2c66affSColin Finck }
1747c2c66affSColin Finck
1748c2c66affSColin Finck // Increase the page count.
1749c2c66affSColin Finck ++pPrinterHandle->pJob->dwTotalPages;
1750c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
1751c2c66affSColin Finck
1752c2c66affSColin Finck Cleanup:
1753c2c66affSColin Finck SetLastError(dwErrorCode);
1754c2c66affSColin Finck return (dwErrorCode == ERROR_SUCCESS);
1755c2c66affSColin Finck }
1756c2c66affSColin Finck
1757c2c66affSColin Finck BOOL WINAPI
LocalWritePrinter(HANDLE hPrinter,PVOID pBuf,DWORD cbBuf,PDWORD pcWritten)1758c2c66affSColin Finck LocalWritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
1759c2c66affSColin Finck {
1760c2c66affSColin Finck BOOL bReturnValue;
1761c2c66affSColin Finck DWORD dwErrorCode;
1762c2c66affSColin Finck PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
1763c2c66affSColin Finck PLOCAL_PORT_HANDLE pPortHandle;
1764c2c66affSColin Finck PLOCAL_PRINTER_HANDLE pPrinterHandle;
1765c2c66affSColin Finck
1766c2c66affSColin Finck TRACE("LocalWritePrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1767c2c66affSColin Finck
1768c2c66affSColin Finck // Sanity checks.
1769c2c66affSColin Finck if (!pHandle)
1770c2c66affSColin Finck {
1771c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1772c2c66affSColin Finck goto Cleanup;
1773c2c66affSColin Finck }
1774c2c66affSColin Finck
1775c2c66affSColin Finck // Port handles are an entirely different thing.
1776c2c66affSColin Finck if (pHandle->HandleType == HandleType_Port)
1777c2c66affSColin Finck {
1778c2c66affSColin Finck pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle;
1779c2c66affSColin Finck
1780c2c66affSColin Finck // Call the monitor's WritePort function.
1781c2c66affSColin Finck if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
1782c2c66affSColin Finck bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnWritePort(pPortHandle->hPort, pBuf, cbBuf, pcWritten);
1783c2c66affSColin Finck else
1784c2c66affSColin Finck bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnWritePort(pPortHandle->hPort, pBuf, cbBuf, pcWritten);
1785c2c66affSColin Finck
1786c2c66affSColin Finck if (!bReturnValue)
1787c2c66affSColin Finck {
1788c2c66affSColin Finck // The WritePort function failed. Return its last error.
1789c2c66affSColin Finck dwErrorCode = GetLastError();
1790c2c66affSColin Finck goto Cleanup;
1791c2c66affSColin Finck }
1792c2c66affSColin Finck
1793c2c66affSColin Finck // We were successful!
1794c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
1795c2c66affSColin Finck goto Cleanup;
1796c2c66affSColin Finck }
1797c2c66affSColin Finck
1798c2c66affSColin Finck // The remaining function deals with Printer handles only.
1799c2c66affSColin Finck if (pHandle->HandleType != HandleType_Printer)
1800c2c66affSColin Finck {
1801c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1802c2c66affSColin Finck goto Cleanup;
1803c2c66affSColin Finck }
1804c2c66affSColin Finck
1805c2c66affSColin Finck pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
1806c2c66affSColin Finck
1807c2c66affSColin Finck // We require StartDocPrinter or AddJob to be called first.
1808c2c66affSColin Finck if (!pPrinterHandle->bStartedDoc)
1809c2c66affSColin Finck {
1810c2c66affSColin Finck dwErrorCode = ERROR_SPL_NO_STARTDOC;
1811c2c66affSColin Finck goto Cleanup;
1812c2c66affSColin Finck }
1813c2c66affSColin Finck
1814c2c66affSColin Finck // TODO: This function is only called when doing non-spooled printing.
1815c2c66affSColin 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).
1816c2c66affSColin Finck #if 0
1817c2c66affSColin Finck // Pass the parameters to WriteFile.
1818c2c66affSColin Finck if (!WriteFile(SOME_SPOOL_FILE_HANDLE, pBuf, cbBuf, pcWritten, NULL))
1819c2c66affSColin Finck {
1820c2c66affSColin Finck dwErrorCode = GetLastError();
1821c2c66affSColin Finck ERR("WriteFile failed with error %lu!\n", GetLastError());
1822c2c66affSColin Finck goto Cleanup;
1823c2c66affSColin Finck }
1824c2c66affSColin Finck #endif
1825c2c66affSColin Finck
1826c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
1827c2c66affSColin Finck
1828c2c66affSColin Finck Cleanup:
1829c2c66affSColin Finck SetLastError(dwErrorCode);
1830c2c66affSColin Finck return (dwErrorCode == ERROR_SUCCESS);
1831c2c66affSColin Finck }
1832c2c66affSColin Finck
1833c2c66affSColin Finck BOOL WINAPI
LocalEndPagePrinter(HANDLE hPrinter)1834c2c66affSColin Finck LocalEndPagePrinter(HANDLE hPrinter)
1835c2c66affSColin Finck {
1836c2c66affSColin Finck DWORD dwErrorCode;
1837c2c66affSColin Finck PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
1838c2c66affSColin Finck
1839c2c66affSColin Finck TRACE("LocalEndPagePrinter(%p)\n", hPrinter);
1840c2c66affSColin Finck
1841c2c66affSColin Finck // Sanity checks.
1842c2c66affSColin Finck if (!pHandle || pHandle->HandleType != HandleType_Printer)
1843c2c66affSColin Finck {
1844c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1845c2c66affSColin Finck goto Cleanup;
1846c2c66affSColin Finck }
1847c2c66affSColin Finck
1848c2c66affSColin Finck // This function doesn't do anything else for now.
1849c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
1850c2c66affSColin Finck
1851c2c66affSColin Finck Cleanup:
1852c2c66affSColin Finck SetLastError(dwErrorCode);
1853c2c66affSColin Finck return (dwErrorCode == ERROR_SUCCESS);
1854c2c66affSColin Finck }
1855c2c66affSColin Finck
1856c2c66affSColin Finck BOOL WINAPI
LocalEndDocPrinter(HANDLE hPrinter)1857c2c66affSColin Finck LocalEndDocPrinter(HANDLE hPrinter)
1858c2c66affSColin Finck {
1859c2c66affSColin Finck BOOL bReturnValue;
1860c2c66affSColin Finck DWORD dwErrorCode;
1861c2c66affSColin Finck PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
1862c2c66affSColin Finck PLOCAL_PORT_HANDLE pPortHandle;
1863c2c66affSColin Finck PLOCAL_PRINTER_HANDLE pPrinterHandle;
1864c2c66affSColin Finck
1865c2c66affSColin Finck TRACE("LocalEndDocPrinter(%p)\n", hPrinter);
1866c2c66affSColin Finck
1867c2c66affSColin Finck // Sanity checks.
1868c2c66affSColin Finck if (!pHandle)
1869c2c66affSColin Finck {
1870c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1871c2c66affSColin Finck goto Cleanup;
1872c2c66affSColin Finck }
1873c2c66affSColin Finck
1874c2c66affSColin Finck // Port handles are an entirely different thing.
1875c2c66affSColin Finck if (pHandle->HandleType == HandleType_Port)
1876c2c66affSColin Finck {
1877c2c66affSColin Finck pPortHandle = (PLOCAL_PORT_HANDLE)pHandle->pSpecificHandle;
1878c2c66affSColin Finck
1879c2c66affSColin Finck // Call the monitor's EndDocPort function.
1880c2c66affSColin Finck if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
1881c2c66affSColin Finck bReturnValue = ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnEndDocPort(pPortHandle->hPort);
1882c2c66affSColin Finck else
1883c2c66affSColin Finck bReturnValue = ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnEndDocPort(pPortHandle->hPort);
1884c2c66affSColin Finck
1885c2c66affSColin Finck if (!bReturnValue)
1886c2c66affSColin Finck {
1887c2c66affSColin Finck // The EndDocPort function failed. Return its last error.
1888c2c66affSColin Finck dwErrorCode = GetLastError();
1889c2c66affSColin Finck goto Cleanup;
1890c2c66affSColin Finck }
1891c2c66affSColin Finck
1892c2c66affSColin Finck // We were successful!
1893c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
1894c2c66affSColin Finck goto Cleanup;
1895c2c66affSColin Finck }
1896c2c66affSColin Finck
1897c2c66affSColin Finck // The remaining function deals with Printer handles only.
1898c2c66affSColin Finck if (pHandle->HandleType != HandleType_Printer)
1899c2c66affSColin Finck {
1900c2c66affSColin Finck dwErrorCode = ERROR_INVALID_HANDLE;
1901c2c66affSColin Finck goto Cleanup;
1902c2c66affSColin Finck }
1903c2c66affSColin Finck
1904c2c66affSColin Finck pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
1905c2c66affSColin Finck
1906c2c66affSColin Finck // We require StartDocPrinter or AddJob to be called first.
1907c2c66affSColin Finck if (!pPrinterHandle->bStartedDoc)
1908c2c66affSColin Finck {
1909c2c66affSColin Finck dwErrorCode = ERROR_SPL_NO_STARTDOC;
1910c2c66affSColin Finck goto Cleanup;
1911c2c66affSColin Finck }
1912c2c66affSColin Finck
1913c2c66affSColin Finck // TODO: Something like ScheduleJob
1914c2c66affSColin Finck
1915c2c66affSColin Finck // Finish the job.
1916c2c66affSColin Finck pPrinterHandle->bStartedDoc = FALSE;
1917c2c66affSColin Finck pPrinterHandle->pJob = NULL;
1918c2c66affSColin Finck dwErrorCode = ERROR_SUCCESS;
1919c2c66affSColin Finck
1920c2c66affSColin Finck Cleanup:
1921c2c66affSColin Finck SetLastError(dwErrorCode);
1922c2c66affSColin Finck return (dwErrorCode == ERROR_SUCCESS);
1923c2c66affSColin Finck }
1924c2c66affSColin Finck
1925c2c66affSColin Finck static void
_LocalClosePortHandle(PLOCAL_PORT_HANDLE pPortHandle)1926c2c66affSColin Finck _LocalClosePortHandle(PLOCAL_PORT_HANDLE pPortHandle)
1927c2c66affSColin Finck {
192862c4b828SJames Tabor FIXME("LocalClosePortHandle\n");
1929c2c66affSColin Finck // Call the monitor's ClosePort function.
1930c2c66affSColin Finck if (pPortHandle->pPort->pPrintMonitor->bIsLevel2)
1931c2c66affSColin Finck ((PMONITOR2)pPortHandle->pPort->pPrintMonitor->pMonitor)->pfnClosePort(pPortHandle->hPort);
1932c2c66affSColin Finck else
1933c2c66affSColin Finck ((LPMONITOREX)pPortHandle->pPort->pPrintMonitor->pMonitor)->Monitor.pfnClosePort(pPortHandle->hPort);
1934c2c66affSColin Finck }
1935c2c66affSColin Finck
1936c2c66affSColin Finck static void
_LocalClosePrinterHandle(PLOCAL_PRINTER_HANDLE pPrinterHandle)1937c2c66affSColin Finck _LocalClosePrinterHandle(PLOCAL_PRINTER_HANDLE pPrinterHandle)
1938c2c66affSColin Finck {
193962c4b828SJames Tabor FIXME("LocalClosePrinterHandle\n");
1940c2c66affSColin Finck // Terminate any started job.
1941c2c66affSColin Finck if (pPrinterHandle->pJob)
1942c2c66affSColin Finck FreeJob(pPrinterHandle->pJob);
1943c2c66affSColin Finck
1944c2c66affSColin Finck // Free memory for the fields.
1945c2c66affSColin Finck DllFreeSplMem(pPrinterHandle->pDevMode);
1946c2c66affSColin Finck DllFreeSplStr(pPrinterHandle->pwszDatatype);
1947c2c66affSColin Finck }
1948c2c66affSColin Finck
1949c2c66affSColin Finck static void
_LocalCloseXcvHandle(PLOCAL_XCV_HANDLE pXcvHandle)1950c2c66affSColin Finck _LocalCloseXcvHandle(PLOCAL_XCV_HANDLE pXcvHandle)
1951c2c66affSColin Finck {
1952c2c66affSColin Finck // Call the monitor's XcvClosePort function.
1953c2c66affSColin Finck if (pXcvHandle->pPrintMonitor->bIsLevel2)
1954c2c66affSColin Finck ((PMONITOR2)pXcvHandle->pPrintMonitor->pMonitor)->pfnXcvClosePort(pXcvHandle->hXcv);
1955c2c66affSColin Finck else
1956c2c66affSColin Finck ((LPMONITOREX)pXcvHandle->pPrintMonitor->pMonitor)->Monitor.pfnXcvClosePort(pXcvHandle->hXcv);
1957c2c66affSColin Finck }
1958c2c66affSColin Finck
1959c2c66affSColin Finck BOOL WINAPI
LocalClosePrinter(HANDLE hPrinter)1960c2c66affSColin Finck LocalClosePrinter(HANDLE hPrinter)
1961c2c66affSColin Finck {
1962c2c66affSColin Finck PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
1963c2c66affSColin Finck
196462c4b828SJames Tabor FIXME("LocalClosePrinter(%p)\n", hPrinter);
1965c2c66affSColin Finck
1966c2c66affSColin Finck if (!pHandle)
1967c2c66affSColin Finck {
1968c2c66affSColin Finck SetLastError(ERROR_INVALID_HANDLE);
1969c2c66affSColin Finck return FALSE;
1970c2c66affSColin Finck }
1971c2c66affSColin Finck
1972c2c66affSColin Finck if (pHandle->HandleType == HandleType_Port)
1973c2c66affSColin Finck {
1974c2c66affSColin Finck _LocalClosePortHandle(pHandle->pSpecificHandle);
1975c2c66affSColin Finck }
1976c2c66affSColin Finck else if (pHandle->HandleType == HandleType_Printer)
1977c2c66affSColin Finck {
1978c2c66affSColin Finck _LocalClosePrinterHandle(pHandle->pSpecificHandle);
1979c2c66affSColin Finck }
1980c2c66affSColin Finck else if (pHandle->HandleType == HandleType_PrintServer)
1981c2c66affSColin Finck {
1982c2c66affSColin Finck // Nothing to do.
1983c2c66affSColin Finck }
1984c2c66affSColin Finck else if (pHandle->HandleType == HandleType_Xcv)
1985c2c66affSColin Finck {
1986c2c66affSColin Finck _LocalCloseXcvHandle(pHandle->pSpecificHandle);
1987c2c66affSColin Finck }
198862c4b828SJames Tabor FIXME("LocalClosePrinter 1\n");
1989c2c66affSColin Finck // Free memory for the handle and the specific handle (if any).
1990c2c66affSColin Finck if (pHandle->pSpecificHandle)
1991c2c66affSColin Finck DllFreeSplMem(pHandle->pSpecificHandle);
199262c4b828SJames Tabor FIXME("LocalClosePrinter 2\n");
1993c2c66affSColin Finck DllFreeSplMem(pHandle);
199462c4b828SJames Tabor FIXME("LocalClosePrinter 3\n");
1995c2c66affSColin Finck return TRUE;
1996c2c66affSColin Finck }
1997