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