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