ReactOS 0.4.16-dev-336-gb667d82
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
14static void _LocalGetPrinterLevel0(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_STRESS* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
15static void _LocalGetPrinterLevel1(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_1W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
16static void _LocalGetPrinterLevel2(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_2W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
17static void _LocalGetPrinterLevel3(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_3* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
18static void _LocalGetPrinterLevel4(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_4W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
19static void _LocalGetPrinterLevel5(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_5W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
20static void _LocalGetPrinterLevel6(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_6* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
21static void _LocalGetPrinterLevel7(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_7W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
22static void _LocalGetPrinterLevel8(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_8W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName);
23static 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),
44};
45
49 FIELD_OFFSET(PRINTER_INFO_1W, pDescription),
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),
59 FIELD_OFFSET(PRINTER_INFO_2W, pLocation),
61 FIELD_OFFSET(PRINTER_INFO_2W, pPrintProcessor),
62 FIELD_OFFSET(PRINTER_INFO_2W, pDatatype),
63 FIELD_OFFSET(PRINTER_INFO_2W, pParameters),
65};
66
68 FIELD_OFFSET(PRINTER_INFO_4W, pPrinterName),
70};
71
73 FIELD_OFFSET(PRINTER_INFO_5W, pPrinterName),
74 FIELD_OFFSET(PRINTER_INFO_5W, pPortName),
76};
77
80static const DWORD dwDeviceNotSelectedTimeout = 15000;
81static const DWORD dwTransmissionRetryTimeout = 45000;
82
83
90static int WINAPI
92{
95
96 return _wcsicmp(A->pwszPrinterName, B->pwszPrinterName);
97}
98
106BOOL
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)
149
150 if (pPrinter->pwszDefaultDatatype)
152
153 if (pPrinter->pwszDescription)
155
156 if (pPrinter->pwszPrinterDriver)
158
159 if (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
317Cleanup:
318 // Inside the loop
319 if (hSubKey)
320 RegCloseKey(hSubKey);
321
322 if (pPrinter)
323 {
324 if (pPrinter->pDefaultDevMode)
326
327 if (pPrinter->pwszDefaultDatatype)
329
330 if (pPrinter->pwszDescription)
332
333 if (pPrinter->pwszPrinterDriver)
335
336 if (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
349VOID
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
390static DWORD
391_LocalEnumPrintersCheckName(DWORD Flags, PCWSTR Name, PWSTR pwszComputerName, PDWORD pcchComputerName)
392{
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 {
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 {
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
485static 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
508static void
509_LocalGetPrinterLevel0(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_STRESS* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
510{
511 size_t cbName;
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
555static 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
610static 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;
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
703static 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
725static void
726_LocalGetPrinterLevel4(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_4W* ppPrinterInfo, PBYTE* ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
727{
728 size_t cbPrinterName;
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
759static 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;
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
800static 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
816static 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
835static 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
858static 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
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
979Cleanup:
980 SetLastError(dwErrorCode);
981 return (dwErrorCode == ERROR_SUCCESS);
982}
983
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
1037Cleanup:
1038 SetLastError(dwErrorCode);
1039 return (dwErrorCode == ERROR_SUCCESS);
1040}
1041
1042static 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
1106Failure:
1107 if (pHandle)
1108 DllFreeSplMem(pHandle);
1109
1110 if (pPortHandle)
1111 DllFreeSplMem(pPortHandle);
1112
1113 return dwErrorCode;
1114}
1115
1116static 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\"!\n", 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
1239Failure:
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
1257static 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");
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
1279static 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
1377Failure:
1378 if (pHandle)
1379 DllFreeSplMem(pHandle);
1380
1381 if (pXcvHandle)
1382 DllFreeSplMem(pXcvHandle);
1383
1384 return dwErrorCode;
1385}
1386
1387//
1388// Dead API
1389//
1392{
1394 return 0;
1395}
1396
1398LocalOpenPrinter(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
1525Cleanup:
1526 if (pwszFirstParameter)
1527 DllFreeSplMem(pwszFirstParameter);
1528
1529 SetLastError(dwErrorCode);
1530 return (dwErrorCode == ERROR_SUCCESS);
1531}
1532
1534LocalReadPrinter(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
1601Cleanup:
1602 SetLastError(dwErrorCode);
1603 return (dwErrorCode == ERROR_SUCCESS);
1604}
1605
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
1718Cleanup:
1719 SetLastError(dwErrorCode);
1720 return dwReturnValue;
1721}
1722
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
1752Cleanup:
1753 SetLastError(dwErrorCode);
1754 return (dwErrorCode == ERROR_SUCCESS);
1755}
1756
1758LocalWritePrinter(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
1828Cleanup:
1829 SetLastError(dwErrorCode);
1830 return (dwErrorCode == ERROR_SUCCESS);
1831}
1832
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
1851Cleanup:
1852 SetLastError(dwErrorCode);
1853 return (dwErrorCode == ERROR_SUCCESS);
1854}
1855
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
1920Cleanup:
1921 SetLastError(dwErrorCode);
1922 return (dwErrorCode == ERROR_SUCCESS);
1923}
1924
1925static 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
1936static 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
1949static 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
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)
1992 FIXME("LocalClosePrinter 2\n");
1993 DllFreeSplMem(pHandle);
1994 FIXME("LocalClosePrinter 3\n");
1995 return TRUE;
1996}
HWND hWnd
Definition: settings.c:17
#define FIXME(fmt,...)
Definition: precomp.h:53
#define ERR(fmt,...)
Definition: precomp.h:57
PBYTE WINAPI PackStrings(PCWSTR *pSource, PBYTE pDest, const DWORD *DestOffsets, PBYTE pEnd)
Definition: tools.c:39
BOOL Error
Definition: chkdsk.c:66
#define RegCloseKey(hKey)
Definition: registry.h:49
Definition: ehthrow.cxx:93
Definition: ehthrow.cxx:54
BOOL WINAPI GetComputerNameW(LPWSTR lpBuffer, LPDWORD lpnSize)
Definition: compname.c:446
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define ERROR_MORE_DATA
Definition: dderror.h:13
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3333
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:2504
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:3662
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4103
#define wcschr
Definition: compat.h:17
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define OPEN_EXISTING
Definition: compat.h:775
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define SetLastError(x)
Definition: compat.h:752
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define GENERIC_READ
Definition: compat.h:135
#define MAX_PATH
Definition: compat.h:34
#define ERROR_INVALID_HANDLE
Definition: compat.h:98
#define CreateFileW
Definition: compat.h:741
#define FILE_SHARE_READ
Definition: compat.h:136
#define ERROR_INVALID_NAME
Definition: compat.h:103
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
VOID WINAPI GetSystemInfo(IN LPSYSTEM_INFO lpSystemInfo)
Definition: sysinfo.c:143
static const WCHAR Cleanup[]
Definition: register.c:80
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
#define MAX_PRINTER_NAME
Definition: fpSetJob.c:25
GLfloat GLfloat p
Definition: glext.h:8902
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
_Check_return_ unsigned long __cdecl wcstoul(_In_z_ const wchar_t *_Str, _Out_opt_ _Deref_post_z_ wchar_t **_EndPtr, _In_ int _Radix)
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
if(dx< 0)
Definition: linetemp.h:194
static HANDLE hXcv
Definition: localmon.c:73
#define ASSERT(a)
Definition: mode.c:44
static LPSTR pName
Definition: security.c:75
static const WCHAR wszEmpty[]
Definition: misc.c:327
struct _SECURITY_DESCRIPTOR * PSECURITY_DESCRIPTOR
Definition: security.c:98
struct _SECURITY_DESCRIPTOR SECURITY_DESCRIPTOR
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define KEY_READ
Definition: nt_native.h:1023
#define DWORD
Definition: nt_native.h:44
#define GENERIC_WRITE
Definition: nt_native.h:90
#define MAXDWORD
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:455
#define L(x)
Definition: ntvdm.h:50
BYTE * PBYTE
Definition: pedump.c:66
DWORD * PDWORD
Definition: pedump.c:68
SKIPLIST GlobalJobList
Definition: jobs.c:11
DWORD WINAPI CreateJob(PLOCAL_PRINTER_HANDLE pPrinterHandle)
Definition: jobs.c:257
void InitializePrinterJobList(PLOCAL_PRINTER pPrinter)
Definition: jobs.c:247
DWORD GetJobFilePath(PCWSTR pwszExtension, DWORD dwJobID, PWSTR pwszOutput)
Definition: jobs.c:146
void FreeJob(PLOCAL_JOB pJob)
Definition: jobs.c:1452
PLOCAL_PRINT_MONITOR FindPrintMonitor(PCWSTR pwszName)
Definition: monitors.c:28
static void _LocalClosePrinterHandle(PLOCAL_PRINTER_HANDLE pPrinterHandle)
Definition: printers.c:1937
static const DWORD dwTransmissionRetryTimeout
Definition: printers.c:81
static DWORD _LocalOpenPortHandle(PWSTR pwszPortName, PHANDLE phPrinter)
Definition: printers.c:1043
static void _LocalGetPrinterLevel1(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_1W *ppPrinterInfo, PBYTE *ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
Definition: printers.c:556
static DWORD _DumpLevel1PrintProviderInformation(PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
Definition: printers.c:486
BOOL WINAPI LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
Definition: printers.c:884
DWORD WINAPI LocalPrinterMessageBox(HANDLE hPrinter, DWORD Error, HWND hWnd, LPWSTR pText, LPWSTR pCaption, DWORD dwType)
Definition: printers.c:1391
void(* PLocalGetPrinterLevelFunc)(PLOCAL_PRINTER, PVOID, PBYTE *, PDWORD, DWORD, PCWSTR)
Definition: printers.c:26
static const DWORD dwDeviceNotSelectedTimeout
Definition: printers.c:80
static DWORD dwPrinterInfo1Offsets[]
Definition: printers.c:46
static DWORD _LocalOpenPrinterHandle(PWSTR pwszPrinterName, PWSTR pwszJobParameter, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
Definition: printers.c:1117
BOOL WINAPI LocalWritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
Definition: printers.c:1758
static DWORD dwPrinterInfo5Offsets[]
Definition: printers.c:72
static void _LocalCloseXcvHandle(PLOCAL_XCV_HANDLE pXcvHandle)
Definition: printers.c:1950
static DWORD _LocalOpenPrintServerHandle(PHANDLE phPrinter)
Definition: printers.c:1258
static int WINAPI _PrinterListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct)
Definition: printers.c:91
static void _LocalGetPrinterLevel0(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_STRESS *ppPrinterInfo, PBYTE *ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
Definition: printers.c:509
static void _LocalGetPrinterLevel8(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_8W *ppPrinterInfo, PBYTE *ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
Definition: printers.c:836
BOOL WINAPI LocalEndPagePrinter(HANDLE hPrinter)
Definition: printers.c:1834
static DWORD dwPrinterInfo0Offsets[]
Definition: printers.c:41
static void _LocalGetPrinterLevel6(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_6 *ppPrinterInfo, PBYTE *ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
Definition: printers.c:801
BOOL WINAPI LocalStartPagePrinter(HANDLE hPrinter)
Definition: printers.c:1724
static const PLocalGetPrinterLevelFunc pfnGetPrinterLevels[]
Definition: printers.c:28
BOOL WINAPI LocalReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
Definition: printers.c:1534
static void _LocalClosePortHandle(PLOCAL_PORT_HANDLE pPortHandle)
Definition: printers.c:1926
static void _LocalGetPrinterLevel7(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_7W *ppPrinterInfo, PBYTE *ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
Definition: printers.c:817
VOID BroadcastChange(PLOCAL_HANDLE pHandle)
Definition: printers.c:350
static DWORD _LocalOpenXcvHandle(PWSTR pwszParameter, PHANDLE phPrinter)
Definition: printers.c:1280
BOOL WINAPI LocalClosePrinter(HANDLE hPrinter)
Definition: printers.c:1960
static void _LocalGetPrinterLevel5(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_5W *ppPrinterInfo, PBYTE *ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
Definition: printers.c:760
BOOL WINAPI LocalOpenPrinter(PWSTR lpPrinterName, HANDLE *phPrinter, PPRINTER_DEFAULTSW pDefault)
Definition: printers.c:1398
static DWORD dwPrinterInfo2Offsets[]
Definition: printers.c:53
static DWORD dwPrinterInfo4Offsets[]
Definition: printers.c:67
BOOL WINAPI LocalGetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
Definition: printers.c:985
DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
Definition: printers.c:1607
static void _LocalGetPrinterLevel3(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_3 *ppPrinterInfo, PBYTE *ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
Definition: printers.c:704
SKIPLIST PrinterList
Definition: printers.c:11
static void _LocalGetPrinterLevel4(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_4W *ppPrinterInfo, PBYTE *ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
Definition: printers.c:726
static void _LocalGetPrinterLevel2(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_2W *ppPrinterInfo, PBYTE *ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
Definition: printers.c:611
static DWORD _LocalEnumPrintersCheckName(DWORD Flags, PCWSTR Name, PWSTR pwszComputerName, PDWORD pcchComputerName)
Definition: printers.c:391
static void _LocalGetPrinterLevel9(PLOCAL_PRINTER pPrinter, PPRINTER_INFO_9W *ppPrinterInfo, PBYTE *ppPrinterInfoEnd, PDWORD pcbNeeded, DWORD cchComputerName, PCWSTR wszComputerName)
Definition: printers.c:859
BOOL WINAPI LocalEndDocPrinter(HANDLE hPrinter)
Definition: printers.c:1857
struct _MONITOR2 * PMONITOR2
struct _MONITOREX * LPMONITOREX
DWORD WINAPI GetVersion()
Definition: redirtest.c:5
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
_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)
_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)
@ Monitor
Definition: video.h:270
PVOID LookupElementSkiplist(PSKIPLIST Skiplist, PVOID Element, PDWORD ElementIndex)
Definition: skiplist.c:357
BOOL InsertElementSkiplist(PSKIPLIST Skiplist, PVOID Element)
Definition: skiplist.c:250
void InitializeSkiplist(PSKIPLIST Skiplist, PSKIPLIST_ALLOCATE_ROUTINE AllocateRoutine, PSKIPLIST_COMPARE_ROUTINE CompareRoutine, PSKIPLIST_FREE_ROUTINE FreeRoutine)
Definition: skiplist.c:220
void(WINAPI * PSKIPLIST_FREE_ROUTINE)(PVOID)
Definition: skiplist.h:24
#define _countof(array)
Definition: sndvol32.h:70
#define TRACE(s)
Definition: solgame.cpp:4
struct _PRINTER_INFO_STRESS PRINTER_INFO_STRESS
STRSAFEAPI StringCbCopyExW(STRSAFE_LPWSTR pszDest, size_t cbDest, STRSAFE_LPCWSTR pszSrc, STRSAFE_LPWSTR *ppszDestEnd, size_t *pcbRemaining, STRSAFE_DWORD dwFlags)
Definition: strsafe.h:210
STRSAFEAPI StringCchCopyW(STRSAFE_LPWSTR pszDest, size_t cchDest, STRSAFE_LPCWSTR pszSrc)
Definition: strsafe.h:149
LPWSTR pDatatype
Definition: winspool.h:618
LPWSTR pDocName
Definition: winspool.h:616
PVOID pSpecificHandle
Definition: precomp.h:208
enum _LOCAL_HANDLE::@5125 HandleType
DWORD dwJobID
Definition: precomp.h:140
PLOCAL_PRINTER pPrinter
Definition: precomp.h:144
PLOCAL_PRINT_PROCESSOR pPrintProcessor
Definition: precomp.h:145
DWORD dwTotalPages
Definition: precomp.h:155
PWSTR pwszDatatype
Definition: precomp.h:151
PWSTR pwszDocumentName
Definition: precomp.h:150
PLOCAL_PORT pPort
Definition: precomp.h:183
PWSTR pwszName
Definition: precomp.h:90
PLOCAL_PRINT_MONITOR pPrintMonitor
Definition: precomp.h:91
PLOCAL_JOB pNextJobToProcess
Definition: precomp.h:92
PLOCAL_PRINTER pPrinter
Definition: precomp.h:171
PLOCAL_JOB pJob
Definition: precomp.h:172
PDEVMODEW pDevMode
Definition: precomp.h:174
PWSTR pwszDefaultDatatype
Definition: precomp.h:126
PLOCAL_PORT pPort
Definition: precomp.h:129
PWSTR pwszPrinterName
Definition: precomp.h:119
PWSTR pwszPrinterDriver
Definition: precomp.h:124
DWORD dwAttributes
Definition: precomp.h:121
PWSTR pwszLocation
Definition: precomp.h:123
PLOCAL_PRINT_PROCESSOR pPrintProcessor
Definition: precomp.h:128
PWSTR pwszDescription
Definition: precomp.h:125
PDEVMODEW pDefaultDevMode
Definition: precomp.h:127
SKIPLIST JobList
Definition: precomp.h:130
DWORD dwStatus
Definition: precomp.h:122
PLOCAL_PRINT_MONITOR pPrintMonitor
Definition: precomp.h:192
LPDEVMODEW pDevMode
Definition: winspool.h:862
struct _SKIPLIST_NODE * Next[SKIPLIST_LEVELS]
Definition: skiplist.h:30
PVOID Element
Definition: skiplist.h:31
SKIPLIST_NODE Head
Definition: skiplist.h:37
DWORD NodeCount
Definition: skiplist.h:39
DWORD dwNumberOfProcessors
Definition: winbase.h:1202
WORD wProcessorLevel
Definition: winbase.h:1205
DWORD dwProcessorType
Definition: winbase.h:1203
WORD wProcessorArchitecture
Definition: winbase.h:1194
WORD dmDriverExtra
Definition: wingdi.h:1621
WORD dmSize
Definition: wingdi.h:1620
#define towlower(c)
Definition: wctype.h:97
LPCSTR pText
Definition: txtscale.cpp:79
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
unsigned char * LPBYTE
Definition: typedefs.h:53
void * PVOID
Definition: typedefs.h:50
PVOID HANDLE
Definition: typedefs.h:73
uint32_t * LPDWORD
Definition: typedefs.h:59
BOOL WINAPI DllFreeSplMem(PVOID pMem)
Definition: memory.c:112
PVOID WINAPI DllAllocSplMem(DWORD dwBytes)
Definition: memory.c:95
BOOL WINAPI DllFreeSplStr(PWSTR pwszString)
Definition: memory.c:130
PWSTR WINAPI AllocSplStr(PCWSTR pwszInput)
Definition: memory.c:56
BOOL WINAPI ReallocSplStr(PWSTR *ppwszString, PCWSTR pwszInput)
Definition: memory.c:195
HKEY hPrintersKey
Definition: main.c:12
PCWSTR wszPrintProviderInfo[3]
Definition: main.c:27
PLOCAL_PORT FindPort(PCWSTR pwszName)
Definition: ports.c:15
struct _LOCAL_PRINTER * PLOCAL_PRINTER
Definition: precomp.h:62
struct _LOCAL_PORT_HANDLE * PLOCAL_PORT_HANDLE
Definition: precomp.h:59
BOOL InitializePrinterList(void)
Definition: printers.c:107
PDEVMODEW DuplicateDevMode(PDEVMODEW pInput)
Definition: tools.c:61
PLOCAL_PRINT_PROCESSOR FindPrintProcessor(PCWSTR pwszName)
struct _LOCAL_PRINTER_HANDLE * PLOCAL_PRINTER_HANDLE
Definition: precomp.h:63
BOOL FindDatatype(const PLOCAL_PRINT_PROCESSOR pPrintProcessor, PCWSTR pwszDatatype)
PWSTR AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName)
Definition: tools.c:26
#define IS_VALID_JOB_ID(ID)
Definition: precomp.h:38
struct _LOCAL_HANDLE * PLOCAL_HANDLE
Definition: precomp.h:56
#define ZeroMemory
Definition: winbase.h:1737
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define CopyMemory
Definition: winbase.h:1735
#define MAX_COMPUTERNAME_LENGTH
Definition: winbase.h:269
_In_ DWORD _Out_ PDWORD pcbNeeded
Definition: winddi.h:3828
LONG_PTR LPARAM
Definition: windef.h:208
#define WINAPI
Definition: msvc.h:6
#define ERROR_INVALID_DATATYPE
Definition: winerror.h:1111
#define ERROR_INVALID_LEVEL
Definition: winerror.h:196
#define ERROR_INVALID_PRINTER_NAME
Definition: winerror.h:1108
#define ERROR_SPL_NO_STARTDOC
Definition: winerror.h:1208
struct _devicemodeW * PDEVMODEW
struct _PRINTER_INFO_8W PRINTER_INFO_8W
#define PRINTER_ENUM_SHARED
Definition: winspool.h:901
struct _PRINTER_INFO_5W PRINTER_INFO_5W
#define SERVER_EXECUTE
Definition: winspool.h:1378
#define PRINTER_ENUM_LOCAL
Definition: winspool.h:896
struct _PRINTER_INFO_3 PRINTER_INFO_3
struct _PRINTER_INFO_1W PRINTER_INFO_1W
struct _PRINTER_INFO_2W PRINTER_INFO_2W
#define PRINTER_ENUM_NETWORK
Definition: winspool.h:902
struct _PRINTER_INFO_1W * PPRINTER_INFO_1W
struct _PRINTER_INFO_9W PRINTER_INFO_9W
struct _PRINTER_INFO_4W PRINTER_INFO_4W
struct _PRINTER_INFO_6 PRINTER_INFO_6
#define PRINTER_ENUM_ICON8
Definition: winspool.h:915
#define PRINTER_ENUM_NAME
Definition: winspool.h:899
#define PRINTER_ENUM_REMOTE
Definition: winspool.h:900
#define PRINTER_ENUM_CONNECTIONS
Definition: winspool.h:897
struct _DOC_INFO_1W * PDOC_INFO_1W
#define DSPRINT_UNPUBLISH
Definition: winspool.h:149
struct _PRINTER_INFO_7W PRINTER_INFO_7W
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
#define HWND_BROADCAST
Definition: winuser.h:1207
#define WM_DEVMODECHANGE
Definition: winuser.h:1634
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:56
_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:191
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
Allocation
Definition: exfuncs.h:598
_IRQL_requires_same_ _In_ PVOID _In_ PVOID SecondStruct
Definition: rtltypes.h:403
_IRQL_requires_same_ _In_ PVOID FirstStruct
Definition: rtltypes.h:402
__wchar_t WCHAR
Definition: xmlstorage.h:180
WCHAR * LPWSTR
Definition: xmlstorage.h:184