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