ReactOS 0.4.15-dev-7953-g1f49173
jobs.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 for managing print jobs
5 * COPYRIGHT: Copyright 2015-2017 Colin Finck (colin@reactos.org)
6 */
7
8#include "precomp.h"
9
10// Global Variables
12
13// Local Variables
15
16// Local Constants
18 FIELD_OFFSET(JOB_INFO_1W, pPrinterName),
19 FIELD_OFFSET(JOB_INFO_1W, pMachineName),
21 FIELD_OFFSET(JOB_INFO_1W, pDocument),
22 FIELD_OFFSET(JOB_INFO_1W, pDatatype),
25};
26
28 FIELD_OFFSET(JOB_INFO_2W, pPrinterName),
29 FIELD_OFFSET(JOB_INFO_2W, pMachineName),
31 FIELD_OFFSET(JOB_INFO_2W, pDocument),
32 FIELD_OFFSET(JOB_INFO_2W, pNotifyName),
33 FIELD_OFFSET(JOB_INFO_2W, pDatatype),
34 FIELD_OFFSET(JOB_INFO_2W, pPrintProcessor),
35 FIELD_OFFSET(JOB_INFO_2W, pParameters),
36 FIELD_OFFSET(JOB_INFO_2W, pDriverName),
39};
40
41
57static __inline BOOL
59{
60 if (!pwszA && !pwszB)
61 return TRUE;
62
63 if (pwszA && !pwszB)
64 return FALSE;
65
66 if (!pwszA && pwszB)
67 return FALSE;
68
69 return (wcscmp(pwszA, pwszB) == 0);
70}
71
72static BOOL
74{
76
78 {
79 // This ID is already taken. Try the next one.
81 }
82
84 {
85 ERR("Job ID %lu isn't valid!\n", _dwLastJobID);
86 return FALSE;
87 }
88
89 *dwJobID = _dwLastJobID;
90 return TRUE;
91}
92
99static int WINAPI
101{
104
105 return A->dwJobID - B->dwJobID;
106}
107
114static int WINAPI
116{
119 int iComparison;
120 FILETIME ftSubmittedA;
121 FILETIME ftSubmittedB;
122
123 // First compare the priorities to determine the order.
124 // The job with a higher priority shall come first.
125 iComparison = A->dwPriority - B->dwPriority;
126 if (iComparison != 0)
127 return iComparison;
128
129 // Both have the same priority, so go by creation time.
130 if (!SystemTimeToFileTime(&A->stSubmitted, &ftSubmittedA))
131 {
132 ERR("SystemTimeToFileTime failed for A with error %lu!\n", GetLastError());
133 return 0;
134 }
135
136 if (!SystemTimeToFileTime(&B->stSubmitted, &ftSubmittedB))
137 {
138 ERR("SystemTimeToFileTime failed for B with error %lu!\n", GetLastError());
139 return 0;
140 }
141
142 return CompareFileTime(&ftSubmittedA, &ftSubmittedB);
143}
144
145DWORD
146GetJobFilePath(PCWSTR pwszExtension, DWORD dwJobID, PWSTR pwszOutput)
147{
148 TRACE("GetJobFilePath(%S, %lu, %p)\n", pwszExtension, dwJobID, pwszOutput);
149
150 if (pwszOutput)
151 {
152 CopyMemory(pwszOutput, wszJobDirectory, cchJobDirectory * sizeof(WCHAR));
153 swprintf(&pwszOutput[cchJobDirectory], L"\\%05lu.%s", dwJobID, pwszExtension);
154 }
155
156 // pwszExtension may be L"SPL" or L"SHD", same length for both!
157 return (cchJobDirectory + sizeof("\\?????.SPL")) * sizeof(WCHAR);
158}
159
160BOOL
162{
163 const WCHAR wszPath[] = L"\\?????.SHD";
164 const DWORD cchPath = _countof(wszPath) - 1;
165
166 DWORD dwErrorCode;
167 DWORD dwJobID;
168 HANDLE hFind;
169 PLOCAL_JOB pJob = NULL;
170 PWSTR p;
171 WCHAR wszFullPath[MAX_PATH];
172 WIN32_FIND_DATAW FindData;
173
174 TRACE("InitializeGlobalJobList()\n");
175
176 // This one is incremented in _GetNextJobID.
177 _dwLastJobID = 0;
178
179 // Initialize an empty list for all jobs of all local printers.
180 // We will search it by Job ID (supply a pointer to a DWORD in LookupElementSkiplist).
182
183 // Construct the full path search pattern.
184 CopyMemory(wszFullPath, wszJobDirectory, cchJobDirectory * sizeof(WCHAR));
185 CopyMemory(&wszFullPath[cchJobDirectory], wszPath, (cchPath + 1) * sizeof(WCHAR));
186
187 // Use the search pattern to look for unfinished jobs serialized in shadow files (.SHD)
188 hFind = FindFirstFileW(wszFullPath, &FindData);
189 if (hFind == INVALID_HANDLE_VALUE)
190 {
191 // No unfinished jobs found.
192 dwErrorCode = ERROR_SUCCESS;
193 goto Cleanup;
194 }
195
196 do
197 {
198 // Skip possible subdirectories.
199 if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
200 continue;
201
202 // Extract the Job ID and verify the file name format at the same time.
203 // This includes all valid names (like "00005.SHD") and excludes invalid ones (like "10ABC.SHD").
204 dwJobID = wcstoul(FindData.cFileName, &p, 10);
205 if (!IS_VALID_JOB_ID(dwJobID))
206 continue;
207
208 if (wcsicmp(p, L".SHD") != 0)
209 continue;
210
211 // This shadow file has a valid name. Construct the full path and try to load it.
212 GetJobFilePath(L"SHD", dwJobID, wszFullPath);
213 pJob = ReadJobShadowFile(wszFullPath);
214 if (!pJob)
215 continue;
216
217 // Add it to the Global Job List.
219 {
220 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
221 ERR("InsertElementSkiplist failed for job %lu for the GlobalJobList!\n", pJob->dwJobID);
222 goto Cleanup;
223 }
224
225 // Add it to the Printer's Job List.
226 if (!InsertElementSkiplist(&pJob->pPrinter->JobList, pJob))
227 {
228 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
229 ERR("InsertElementSkiplist failed for job %lu for the Printer's Job List!\n", pJob->dwJobID);
230 goto Cleanup;
231 }
232 }
233 while (FindNextFileW(hFind, &FindData));
234
235 dwErrorCode = ERROR_SUCCESS;
236
237Cleanup:
238 // Outside the loop
239 if (hFind)
240 FindClose(hFind);
241
242 SetLastError(dwErrorCode);
243 return (dwErrorCode == ERROR_SUCCESS);
244}
245
246void
248{
249 TRACE("InitializePrinterJobList(%p)\n", pPrinter);
250
251 // Initialize an empty list for this printer's jobs.
252 // This one is only for sorting the jobs. If you need to lookup a job, search the GlobalJobList by Job ID.
254}
255
258{
259 const WCHAR wszDoubleBackslash[] = L"\\";
260 const DWORD cchDoubleBackslash = _countof(wszDoubleBackslash) - 1;
261
262 DWORD cchMachineName;
263 DWORD cchUserName;
264 DWORD dwErrorCode;
265 PLOCAL_JOB pJob;
266 RPC_BINDING_HANDLE hServerBinding = NULL;
267 RPC_WSTR pwszBinding = NULL;
268 RPC_WSTR pwszMachineName = NULL;
269
270 TRACE("CreateJob(%p)\n", pPrinterHandle);
271
272 // Create a new job.
273 pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
274 if (!pJob)
275 {
276 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
277 ERR("DllAllocSplMem failed!\n");
278 goto Cleanup;
279 }
280
281 // Reserve an ID for this job.
282 if (!_GetNextJobID(&pJob->dwJobID))
283 {
284 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
285 goto Cleanup;
286 }
287
288 // Copy over defaults to the LOCAL_JOB structure.
289 pJob->pPrinter = pPrinterHandle->pPrinter;
290 pJob->pPrintProcessor = pPrinterHandle->pPrinter->pPrintProcessor;
291 pJob->dwPriority = DEF_PRIORITY;
293 pJob->pwszDatatype = AllocSplStr(pPrinterHandle->pwszDatatype);
295 pJob->pDevMode = DuplicateDevMode(pPrinterHandle->pDevMode);
297
298 // Get the user name for the Job.
299 cchUserName = UNLEN + 1;
300 pJob->pwszUserName = DllAllocSplMem(cchUserName * sizeof(WCHAR));
301 if (!GetUserNameW(pJob->pwszUserName, &cchUserName))
302 {
303 dwErrorCode = GetLastError();
304 ERR("GetUserNameW failed with error %lu!\n", dwErrorCode);
305 goto Cleanup;
306 }
307
308 // FIXME: For now, pwszNotifyName equals pwszUserName.
310
311 // Get the name of the machine that submitted the Job over RPC.
312 dwErrorCode = RpcBindingServerFromClient(NULL, &hServerBinding);
313 if (dwErrorCode != RPC_S_OK)
314 {
315 ERR("RpcBindingServerFromClient failed with status %lu!\n", dwErrorCode);
316 goto Cleanup;
317 }
318
319 dwErrorCode = RpcBindingToStringBindingW(hServerBinding, &pwszBinding);
320 if (dwErrorCode != RPC_S_OK)
321 {
322 ERR("RpcBindingToStringBindingW failed with status %lu!\n", dwErrorCode);
323 goto Cleanup;
324 }
325
326 dwErrorCode = RpcStringBindingParseW(pwszBinding, NULL, NULL, &pwszMachineName, NULL, NULL);
327 if (dwErrorCode != RPC_S_OK)
328 {
329 ERR("RpcStringBindingParseW failed with status %lu!\n", dwErrorCode);
330 goto Cleanup;
331 }
332
333 cchMachineName = wcslen(pwszMachineName);
334 pJob->pwszMachineName = DllAllocSplMem((cchMachineName + cchDoubleBackslash + 1) * sizeof(WCHAR));
335 CopyMemory(pJob->pwszMachineName, wszDoubleBackslash, cchDoubleBackslash * sizeof(WCHAR));
336 CopyMemory(&pJob->pwszMachineName[cchDoubleBackslash], pwszMachineName, (cchMachineName + 1) * sizeof(WCHAR));
337
338 // Add the job to the Global Job List.
340 {
341 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
342 ERR("InsertElementSkiplist failed for job %lu for the GlobalJobList!\n", pJob->dwJobID);
343 goto Cleanup;
344 }
345
346 // Add the job at the end of the Printer's Job List.
347 // As all new jobs are created with default priority, we can be sure that it would always be inserted at the end.
348 if (!InsertTailElementSkiplist(&pJob->pPrinter->JobList, pJob))
349 {
350 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
351 ERR("InsertTailElementSkiplist failed for job %lu for the Printer's Job List!\n", pJob->dwJobID);
352 goto Cleanup;
353 }
354
355 // We were successful!
356 pPrinterHandle->bStartedDoc = TRUE;
357 pPrinterHandle->pJob = pJob;
358 dwErrorCode = ERROR_SUCCESS;
359
360 // Don't let the cleanup routine free this.
361 pJob = NULL;
362
363Cleanup:
364 if (pJob)
365 DllFreeSplMem(pJob);
366
367 if (pwszMachineName)
368 RpcStringFreeW(&pwszMachineName);
369
370 if (pwszBinding)
371 RpcStringFreeW(&pwszBinding);
372
373 if (hServerBinding)
374 RpcBindingFree(&hServerBinding);
375
376 return dwErrorCode;
377}
378
381{
382 ADDJOB_INFO_1W AddJobInfo1;
383 DWORD dwErrorCode;
384 PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
385 PLOCAL_PRINTER_HANDLE pPrinterHandle;
386
387 TRACE("LocalAddJob(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pData, cbBuf, pcbNeeded);
388
389 // Check if this is a printer handle.
390 if (pHandle->HandleType != HandleType_Printer)
391 {
392 dwErrorCode = ERROR_INVALID_HANDLE;
393 goto Cleanup;
394 }
395
396 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
397
398 // This handle must not have started a job yet!
399 if (pPrinterHandle->pJob)
400 {
401 dwErrorCode = ERROR_INVALID_HANDLE;
402 goto Cleanup;
403 }
404
405 // Check if this is the right structure level.
406 if (Level != 1)
407 {
408 dwErrorCode = ERROR_INVALID_LEVEL;
409 goto Cleanup;
410 }
411
412 // Check if the printer is set to do direct printing.
413 // The Job List isn't used in this case.
414 if (pPrinterHandle->pPrinter->dwAttributes & PRINTER_ATTRIBUTE_DIRECT)
415 {
416 dwErrorCode = ERROR_INVALID_ACCESS;
417 goto Cleanup;
418 }
419
420 // Check if the supplied buffer is large enough.
421 *pcbNeeded = sizeof(ADDJOB_INFO_1W) + GetJobFilePath(L"SPL", 0, NULL);
422 if (cbBuf < *pcbNeeded)
423 {
424 dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
425 goto Cleanup;
426 }
427
428 // All requirements are met - create a new job.
429 dwErrorCode = CreateJob(pPrinterHandle);
430 if (dwErrorCode != ERROR_SUCCESS)
431 goto Cleanup;
432
433 // Mark that this job was started with AddJob (so that it can be scheduled for printing with ScheduleJob).
434 pPrinterHandle->pJob->bAddedJob = TRUE;
435
436 // Return a proper ADDJOB_INFO_1W structure.
437 AddJobInfo1.JobId = pPrinterHandle->pJob->dwJobID;
438 AddJobInfo1.Path = (PWSTR)(pData + sizeof(ADDJOB_INFO_1W));
439
440 CopyMemory(pData, &AddJobInfo1, sizeof(ADDJOB_INFO_1W));
441 GetJobFilePath(L"SPL", AddJobInfo1.JobId, AddJobInfo1.Path);
442
443Cleanup:
444 SetLastError(dwErrorCode);
445 return (dwErrorCode == ERROR_SUCCESS);
446}
447
448
449static void
451{
452 DWORD cbDatatype;
453 DWORD cbDocumentName = 0;
454 DWORD cbMachineName;
455 DWORD cbPrinterName;
456 DWORD cbStatus = 0;
457 DWORD cbUserName = 0;
458 PCWSTR pwszStrings[6];
459
460 // Calculate the string lengths.
461 if (!ppJobInfo)
462 {
463 cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR);
464 cbMachineName = (wcslen(pJob->pwszMachineName) + 1) * sizeof(WCHAR);
465 cbPrinterName = (wcslen(pJob->pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
466
467 // These values are optional.
468 if (pJob->pwszDocumentName)
469 cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR);
470
471 if (pJob->pwszStatus)
472 cbStatus = (wcslen(pJob->pwszStatus) + 1) * sizeof(WCHAR);
473
474 if (pJob->pwszUserName)
475 cbUserName = (wcslen(pJob->pwszUserName) + 1) * sizeof(WCHAR);
476
477 *pcbNeeded += sizeof(JOB_INFO_1W) + cbDatatype + cbDocumentName + cbMachineName + cbPrinterName + cbStatus + cbUserName;
478 return;
479 }
480
481 // Set the general fields.
482 (*ppJobInfo)->JobId = pJob->dwJobID;
483 (*ppJobInfo)->Status = pJob->dwStatus;
484 (*ppJobInfo)->Priority = pJob->dwPriority;
485 (*ppJobInfo)->TotalPages = pJob->dwTotalPages;
486 (*ppJobInfo)->PagesPrinted = pJob->dwPagesPrinted;
487 CopyMemory(&(*ppJobInfo)->Submitted, &pJob->stSubmitted, sizeof(SYSTEMTIME));
488
489 // Position in JOB_INFO_1W is the 1-based index of the job in the processing queue.
490 // Retrieve this through the element index of the job in the Printer's Job List.
491 if (!LookupElementSkiplist(&pJob->pPrinter->JobList, pJob, &(*ppJobInfo)->Position))
492 {
493 ERR("pJob could not be located in the Printer's Job List!\n");
494 return;
495 }
496
497 // Make the index 1-based.
498 ++(*ppJobInfo)->Position;
499
500 // Set the pPrinterName field.
501 pwszStrings[0] = pJob->pPrinter->pwszPrinterName;
502
503 // Set the pMachineName field.
504 pwszStrings[1] = pJob->pwszMachineName;
505
506 // Set the pUserName field.
507 pwszStrings[2] = pJob->pwszUserName;
508
509 // Set the pDocument field.
510 pwszStrings[3] = pJob->pwszDocumentName;
511
512 // Set the pDatatype field.
513 pwszStrings[4] = pJob->pwszDatatype;
514
515 // Set the pStatus field.
516 pwszStrings[5] = pJob->pwszStatus;
517
518 // Finally copy the structure and advance to the next one in the output buffer.
519 *ppJobInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppJobInfo), dwJobInfo1Offsets, *ppJobInfoEnd);
520 (*ppJobInfo)++;
521}
522
523static void
525{
526 DWORD cbDatatype;
527 DWORD cbDevMode;
528 DWORD cbDocumentName = 0;
529 DWORD cbDriverName;
530 DWORD cbMachineName;
531 DWORD cbNotifyName = 0;
532 DWORD cbPrinterName;
533 DWORD cbPrintProcessor;
534 DWORD cbPrintProcessorParameters = 0;
535 DWORD cbStatus = 0;
536 DWORD cbUserName = 0;
537 FILETIME ftNow;
538 FILETIME ftSubmitted;
539 PCWSTR pwszStrings[10];
540 ULARGE_INTEGER uliNow;
541 ULARGE_INTEGER uliSubmitted;
542
543 // Calculate the string lengths.
544 cbDevMode = pJob->pDevMode->dmSize + pJob->pDevMode->dmDriverExtra;
545
546 if (!ppJobInfo)
547 {
548 cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR);
549 cbDriverName = (wcslen(pJob->pPrinter->pwszPrinterDriver) + 1) * sizeof(WCHAR);
550 cbMachineName = (wcslen(pJob->pwszMachineName) + 1) * sizeof(WCHAR);
551 cbPrinterName = (wcslen(pJob->pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
552 cbPrintProcessor = (wcslen(pJob->pPrintProcessor->pwszName) + 1) * sizeof(WCHAR);
553
554 // These values are optional.
555 if (pJob->pwszDocumentName)
556 cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR);
557
558 if (pJob->pwszNotifyName)
559 cbNotifyName = (wcslen(pJob->pwszNotifyName) + 1) * sizeof(WCHAR);
560
562 cbPrintProcessorParameters = (wcslen(pJob->pwszPrintProcessorParameters) + 1) * sizeof(WCHAR);
563
564 if (pJob->pwszStatus)
565 cbStatus = (wcslen(pJob->pwszStatus) + 1) * sizeof(WCHAR);
566
567 if (pJob->pwszUserName)
568 cbUserName = (wcslen(pJob->pwszUserName) + 1) * sizeof(WCHAR);
569
570 *pcbNeeded += sizeof(JOB_INFO_2W) + cbDatatype + cbDevMode + cbDocumentName + cbDriverName + cbMachineName + cbNotifyName + cbPrinterName + cbPrintProcessor + cbPrintProcessorParameters + cbStatus + cbUserName;
571 return;
572 }
573
574 // Set the general fields.
575 (*ppJobInfo)->JobId = pJob->dwJobID;
576 (*ppJobInfo)->Status = pJob->dwStatus;
577 (*ppJobInfo)->Priority = pJob->dwPriority;
578 (*ppJobInfo)->StartTime = pJob->dwStartTime;
579 (*ppJobInfo)->UntilTime = pJob->dwUntilTime;
580 (*ppJobInfo)->TotalPages = pJob->dwTotalPages;
581 (*ppJobInfo)->PagesPrinted = pJob->dwPagesPrinted;
582 CopyMemory(&(*ppJobInfo)->Submitted, &pJob->stSubmitted, sizeof(SYSTEMTIME));
583
584 // Time in JOB_INFO_2W is the number of milliseconds elapsed since the job was submitted. Calculate this time.
585 if (!SystemTimeToFileTime(&pJob->stSubmitted, &ftSubmitted))
586 {
587 ERR("SystemTimeToFileTime failed with error %lu!\n", GetLastError());
588 return;
589 }
590
592 uliSubmitted.LowPart = ftSubmitted.dwLowDateTime;
593 uliSubmitted.HighPart = ftSubmitted.dwHighDateTime;
594 uliNow.LowPart = ftNow.dwLowDateTime;
595 uliNow.HighPart = ftNow.dwHighDateTime;
596 (*ppJobInfo)->Time = (DWORD)((uliNow.QuadPart - uliSubmitted.QuadPart) / 10000);
597
598 // Position in JOB_INFO_2W is the 1-based index of the job in the processing queue.
599 // Retrieve this through the element index of the job in the Printer's Job List.
600 if (!LookupElementSkiplist(&pJob->pPrinter->JobList, pJob, &(*ppJobInfo)->Position))
601 {
602 ERR("pJob could not be located in the Printer's Job List!\n");
603 return;
604 }
605
606 // Make the index 1-based.
607 ++(*ppJobInfo)->Position;
608
609 // FIXME!
610 FIXME("Setting pSecurityDescriptor and Size to 0 for now!\n");
611 (*ppJobInfo)->pSecurityDescriptor = NULL;
612 (*ppJobInfo)->Size = 0;
613
614 // Set the pDevMode field (and copy the DevMode).
615 *ppJobInfoEnd -= cbDevMode;
616 CopyMemory(*ppJobInfoEnd, pJob->pDevMode, cbDevMode);
617 (*ppJobInfo)->pDevMode = (PDEVMODEW)(*ppJobInfoEnd);
618
619 // Set the pPrinterName field.
620 pwszStrings[0] = pJob->pPrinter->pwszPrinterName;
621
622 // Set the pMachineName field.
623 pwszStrings[1] = pJob->pwszMachineName;
624
625 // Set the pUserName field.
626 pwszStrings[2] = pJob->pwszUserName;
627
628 // Set the pDocument field.
629 pwszStrings[3] = pJob->pwszDocumentName;
630
631 // Set the pNotifyName field.
632 pwszStrings[4] = pJob->pwszNotifyName;
633
634 // Set the pDatatype field.
635 pwszStrings[5] = pJob->pwszDatatype;
636
637 // Set the pPrintProcessor field.
638 pwszStrings[6] = pJob->pPrintProcessor->pwszName;
639
640 // Set the pParameters field.
641 pwszStrings[7] = pJob->pwszPrintProcessorParameters;
642
643 // Set the pDriverName field.
644 pwszStrings[8] = pJob->pPrinter->pwszPrinterDriver;
645
646 // Set the pStatus field.
647 pwszStrings[9] = pJob->pwszStatus;
648
649 // Finally copy the structure and advance to the next one in the output buffer.
650 *ppJobInfoEnd = PackStrings(pwszStrings, (PBYTE)(*ppJobInfo), dwJobInfo2Offsets, *ppJobInfoEnd);
651 (*ppJobInfo)++;
652}
653
655LocalGetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded)
656{
657 DWORD dwErrorCode;
658 PBYTE pEnd = &pStart[cbBuf];
659 PLOCAL_HANDLE pHandle;
660 PLOCAL_JOB pJob;
661 PLOCAL_PRINTER_HANDLE pPrinterHandle;
662
663 TRACE("LocalGetJob(%p, %lu, %lu, %p, %lu, %p)\n", hPrinter, JobId, Level, pStart, cbBuf, pcbNeeded);
664
665 // Check if this is a printer handle.
666 pHandle = (PLOCAL_HANDLE)hPrinter;
667 if (pHandle->HandleType != HandleType_Printer)
668 {
669 dwErrorCode = ERROR_INVALID_HANDLE;
670 goto Cleanup;
671 }
672
673 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
674
675 // Get the desired job.
676 pJob = LookupElementSkiplist(&GlobalJobList, &JobId, NULL);
677 if (!pJob || pJob->pPrinter != pPrinterHandle->pPrinter)
678 {
679 dwErrorCode = ERROR_INVALID_PARAMETER;
680 goto Cleanup;
681 }
682
683 if (Level > 2)
684 {
685 // The caller supplied an invalid level for GetJob.
686 dwErrorCode = ERROR_INVALID_LEVEL;
687 goto Cleanup;
688 }
689
690 // Count the required buffer size.
691 *pcbNeeded = 0;
692
693 if (Level == 1)
695 else if (Level == 2)
697
698 // Check if the supplied buffer is large enough.
699 if (cbBuf < *pcbNeeded)
700 {
701 dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
702 goto Cleanup;
703 }
704
705 // Copy over the Job information.
706 pEnd = &pStart[*pcbNeeded];
707
708 if (Level == 1)
709 _LocalGetJobLevel1(pJob, (PJOB_INFO_1W*)&pStart, &pEnd, NULL);
710 else if (Level == 2)
711 _LocalGetJobLevel2(pJob, (PJOB_INFO_2W*)&pStart, &pEnd, NULL);
712
713 dwErrorCode = ERROR_SUCCESS;
714
715Cleanup:
716 SetLastError(dwErrorCode);
717 return (dwErrorCode == ERROR_SUCCESS);
718}
719
720static DWORD
722{
723 DWORD dwErrorCode;
724
725 // First check the validity of the input before changing anything.
726 if (!FindDatatype(pJob->pPrintProcessor, pJobInfo->pDatatype))
727 {
728 dwErrorCode = ERROR_INVALID_DATATYPE;
729 goto Cleanup;
730 }
731
732 // Check if the datatype has changed.
733 if (!_EqualStrings(pJob->pwszDatatype, pJobInfo->pDatatype))
734 {
735 // Use the new value.
736 if (!ReallocSplStr(&pJob->pwszDatatype, pJobInfo->pDatatype))
737 {
738 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
739 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
740 goto Cleanup;
741 }
742 }
743
744 // Check if the document name has changed. An empty string is permitted here!
745 if (!_EqualStrings(pJob->pwszDocumentName, pJobInfo->pDocument))
746 {
747 // Use the new value.
748 if (!ReallocSplStr(&pJob->pwszDocumentName, pJobInfo->pDocument))
749 {
750 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
751 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
752 goto Cleanup;
753 }
754 }
755
756 // Check if the status message has changed. An empty string is permitted here!
757 if (!_EqualStrings(pJob->pwszStatus, pJobInfo->pStatus))
758 {
759 // Use the new value.
760 if (!ReallocSplStr(&pJob->pwszStatus, pJobInfo->pStatus))
761 {
762 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
763 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
764 goto Cleanup;
765 }
766 }
767
768 // Check if the user name has changed. An empty string is permitted here!
769 if (!_EqualStrings(pJob->pwszUserName, pJobInfo->pUserName))
770 {
771 // The new user name doesn't need to exist, so no additional verification is required.
772
773 // Use the new value.
774 if (!ReallocSplStr(&pJob->pwszUserName, pJobInfo->pUserName))
775 {
776 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
777 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
778 goto Cleanup;
779 }
780 }
781
782 // Check if the priority has changed.
783 if (pJob->dwPriority != pJobInfo->Priority && IS_VALID_PRIORITY(pJobInfo->Priority))
784 {
785 // Set the new priority.
786 pJob->dwPriority = pJobInfo->Priority;
787
788 // Remove and reinsert the job in the Printer's Job List.
789 // The Compare function will be used to find the right position now considering the new priority.
792 }
793
794 // Check if the status flags have changed.
795 if (pJob->dwStatus != pJobInfo->Status)
796 {
797 // Only add status flags that make sense.
798 if (pJobInfo->Status & JOB_STATUS_PAUSED)
800
801 if (pJobInfo->Status & JOB_STATUS_ERROR)
802 pJob->dwStatus |= JOB_STATUS_ERROR;
803
804 if (pJobInfo->Status & JOB_STATUS_OFFLINE)
806
807 if (pJobInfo->Status & JOB_STATUS_PAPEROUT)
809 }
810
811 dwErrorCode = ERROR_SUCCESS;
812
813Cleanup:
814 return dwErrorCode;
815}
816
817static DWORD
819{
820 DWORD dwErrorCode;
821 PLOCAL_PRINT_PROCESSOR pPrintProcessor;
822
823 // First check the validity of the input before changing anything.
824 pPrintProcessor = FindPrintProcessor(pJobInfo->pPrintProcessor);
825 if (!pPrintProcessor)
826 {
827 dwErrorCode = ERROR_UNKNOWN_PRINTPROCESSOR;
828 goto Cleanup;
829 }
830
831 if (!FindDatatype(pPrintProcessor, pJobInfo->pDatatype))
832 {
833 dwErrorCode = ERROR_INVALID_DATATYPE;
834 goto Cleanup;
835 }
836
837 // Check if the datatype has changed.
838 if (!_EqualStrings(pJob->pwszDatatype, pJobInfo->pDatatype))
839 {
840 // Use the new value.
841 if (!ReallocSplStr(&pJob->pwszDatatype, pJobInfo->pDatatype))
842 {
843 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
844 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
845 goto Cleanup;
846 }
847 }
848
849 // Check if the document name has changed. An empty string is permitted here!
850 if (!_EqualStrings(pJob->pwszDocumentName, pJobInfo->pDocument))
851 {
852 // Use the new value.
853 if (!ReallocSplStr(&pJob->pwszDocumentName, pJobInfo->pDocument))
854 {
855 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
856 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
857 goto Cleanup;
858 }
859 }
860
861 // Check if the notify name has changed. An empty string is permitted here!
862 if (!_EqualStrings(pJob->pwszNotifyName, pJobInfo->pNotifyName))
863 {
864 // The new notify name doesn't need to exist, so no additional verification is required.
865
866 // Use the new value.
867 if (!ReallocSplStr(&pJob->pwszNotifyName, pJobInfo->pNotifyName))
868 {
869 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
870 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
871 goto Cleanup;
872 }
873 }
874
875 // Check if the Print Processor Parameters have changed. An empty string is permitted here!
877 {
878 // Use the new value.
880 {
881 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
882 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
883 goto Cleanup;
884 }
885 }
886
887 // Check if the Status Message has changed. An empty string is permitted here!
888 if (!_EqualStrings(pJob->pwszStatus, pJobInfo->pStatus))
889 {
890 // Use the new value.
891 if (!ReallocSplStr(&pJob->pwszStatus, pJobInfo->pStatus))
892 {
893 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
894 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
895 goto Cleanup;
896 }
897 }
898
899 // Check if the user name has changed. An empty string is permitted here!
900 if (!_EqualStrings(pJob->pwszUserName, pJobInfo->pUserName))
901 {
902 // The new user name doesn't need to exist, so no additional verification is required.
903
904 // Use the new value.
905 if (!ReallocSplStr(&pJob->pwszUserName, pJobInfo->pUserName))
906 {
907 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
908 ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
909 goto Cleanup;
910 }
911 }
912
913 // Check if the priority has changed.
914 if (pJob->dwPriority != pJobInfo->Priority && IS_VALID_PRIORITY(pJobInfo->Priority))
915 {
916 // Set the new priority.
917 pJob->dwPriority = pJobInfo->Priority;
918
919 // Remove and reinsert the job in the Printer's Job List.
920 // The Compare function will be used to find the right position now considering the new priority.
923 }
924
925 // Check if the status flags have changed.
926 if (pJob->dwStatus != pJobInfo->Status)
927 {
928 // Only add status flags that make sense.
929 if (pJobInfo->Status & JOB_STATUS_PAUSED)
931
932 if (pJobInfo->Status & JOB_STATUS_ERROR)
933 pJob->dwStatus |= JOB_STATUS_ERROR;
934
935 if (pJobInfo->Status & JOB_STATUS_OFFLINE)
937
938 if (pJobInfo->Status & JOB_STATUS_PAPEROUT)
940 }
941
942 dwErrorCode = ERROR_SUCCESS;
943
944Cleanup:
945 return dwErrorCode;
946}
947
949LocalSetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
950{
951 DWORD dwErrorCode = ERROR_SUCCESS;
952 PLOCAL_HANDLE pHandle;
953 PLOCAL_JOB pJob;
954 PLOCAL_PRINTER_HANDLE pPrinterHandle;
955 WCHAR wszFullPath[MAX_PATH];
956
957 TRACE("LocalSetJob(%p, %lu, %lu, %p, %lu)\n", hPrinter, JobId, Level, pJobInfo, Command);
958
959 // Check if this is a printer handle.
960 pHandle = (PLOCAL_HANDLE)hPrinter;
961 if (!pHandle || pHandle->HandleType != HandleType_Printer)
962 {
963 dwErrorCode = ERROR_INVALID_HANDLE;
964 goto Cleanup;
965 }
966
967 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
968
969 // Get the desired job.
970 pJob = LookupElementSkiplist(&GlobalJobList, &JobId, NULL);
971 if (!pJob || pJob->pPrinter != pPrinterHandle->pPrinter)
972 {
973 dwErrorCode = ERROR_INVALID_PARAMETER;
974 goto Cleanup;
975 }
976
977 // Set new job information if a valid level was given.
978 if (Level == 1)
979 dwErrorCode = _LocalSetJobLevel1(pPrinterHandle, pJob, (PJOB_INFO_1W)pJobInfo);
980 else if (Level == 2)
981 dwErrorCode = _LocalSetJobLevel2(pPrinterHandle, pJob, (PJOB_INFO_2W)pJobInfo);
982
983 if (dwErrorCode != ERROR_SUCCESS)
984 goto Cleanup;
985
986 // If we do spooled printing, the job information is written down into a shadow file.
987 if (!(pPrinterHandle->pPrinter->dwAttributes & PRINTER_ATTRIBUTE_DIRECT))
988 {
989 // Write the job data into the shadow file.
990 GetJobFilePath(L"SHD", JobId, wszFullPath);
991 WriteJobShadowFile(wszFullPath, pJob);
992 }
993
994 // Perform an additional command if desired.
995 if (Command)
996 {
998 {
999 // This indicates the end of the Print Job.
1000
1001 // Cancel the Job at the Print Processor.
1002 if (pJob->hPrintProcessor)
1004
1005 FreeJob(pJob);
1006
1007 // TODO: All open handles associated with the job need to be invalidated.
1008 // This certainly needs handle tracking...
1009 }
1010 else
1011 {
1012 ERR("Unimplemented SetJob Command: %lu!\n", Command);
1013 }
1014 }
1015
1016Cleanup:
1017 SetLastError(dwErrorCode);
1018 return (dwErrorCode == ERROR_SUCCESS);
1019}
1020
1022LocalEnumJobs(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
1023{
1024 DWORD dwErrorCode;
1025 DWORD i;
1026 PBYTE pEnd;
1027 PLOCAL_HANDLE pHandle;
1028 PLOCAL_JOB pJob;
1029 PSKIPLIST_NODE pFirstJobNode;
1030 PSKIPLIST_NODE pNode;
1031 PLOCAL_PRINTER_HANDLE pPrinterHandle;
1032
1033 TRACE("LocalEnumJobs(%p, %lu, %lu, %lu, %p, %lu, %p, %p)\n", hPrinter, FirstJob, NoJobs, Level, pStart, cbBuf, pcbNeeded, pcReturned);
1034
1035 // Check if this is a printer handle.
1036 pHandle = (PLOCAL_HANDLE)hPrinter;
1037 if (pHandle->HandleType != HandleType_Printer)
1038 {
1039 dwErrorCode = ERROR_INVALID_HANDLE;
1040 goto Cleanup;
1041 }
1042
1043 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
1044
1045 // Check the level.
1046 if (Level > 2)
1047 {
1048 dwErrorCode = ERROR_INVALID_LEVEL;
1049 goto Cleanup;
1050 }
1051
1052 // Begin counting.
1053 *pcbNeeded = 0;
1054 *pcReturned = 0;
1055
1056 // Lookup the node of the first job requested by the caller in the Printer's Job List.
1057 pFirstJobNode = LookupNodeByIndexSkiplist(&pPrinterHandle->pPrinter->JobList, FirstJob);
1058
1059 // Count the required buffer size and the number of jobs.
1060 i = 0;
1061 pNode = pFirstJobNode;
1062
1063 while (i < NoJobs && pNode)
1064 {
1065 pJob = (PLOCAL_JOB)pNode->Element;
1066
1067 if (Level == 1)
1069 else if (Level == 2)
1071
1072 // We stop either when there are no more jobs in the list or when the caller didn't request more, whatever comes first.
1073 i++;
1074 pNode = pNode->Next[0];
1075 }
1076
1077 // Check if the supplied buffer is large enough.
1078 if (cbBuf < *pcbNeeded)
1079 {
1080 dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
1081 goto Cleanup;
1082 }
1083
1084 // Copy over the Job information.
1085 i = 0;
1086 pNode = pFirstJobNode;
1087 pEnd = &pStart[*pcbNeeded];
1088
1089 while (i < NoJobs && pNode)
1090 {
1091 pJob = (PLOCAL_JOB)pNode->Element;
1092
1093 if (Level == 1)
1094 _LocalGetJobLevel1(pJob, (PJOB_INFO_1W*)&pStart, &pEnd, NULL);
1095 else if (Level == 2)
1096 _LocalGetJobLevel2(pJob, (PJOB_INFO_2W*)&pStart, &pEnd, NULL);
1097
1098 // We stop either when there are no more jobs in the list or when the caller didn't request more, whatever comes first.
1099 i++;
1100 pNode = pNode->Next[0];
1101 }
1102
1103 *pcReturned = i;
1104 dwErrorCode = ERROR_SUCCESS;
1105
1106Cleanup:
1107 SetLastError(dwErrorCode);
1108 return (dwErrorCode == ERROR_SUCCESS);
1109}
1110
1113{
1115 DWORD dwErrorCode;
1117 PLOCAL_JOB pJob;
1118 PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
1119 PLOCAL_PRINTER_HANDLE pPrinterHandle;
1120 WCHAR wszFullPath[MAX_PATH];
1121
1122 TRACE("LocalScheduleJob(%p, %lu)\n", hPrinter, dwJobID);
1123
1124 // Check if this is a printer handle.
1125 if (pHandle->HandleType != HandleType_Printer)
1126 {
1127 dwErrorCode = ERROR_INVALID_HANDLE;
1128 goto Cleanup;
1129 }
1130
1131 pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
1132
1133 // Check if the Job ID is valid.
1134 pJob = LookupElementSkiplist(&GlobalJobList, &dwJobID, NULL);
1135 if (!pJob || pJob->pPrinter != pPrinterHandle->pPrinter)
1136 {
1137 dwErrorCode = ERROR_INVALID_PARAMETER;
1138 goto Cleanup;
1139 }
1140
1141 // Check if this Job was started with AddJob.
1142 if (!pJob->bAddedJob)
1143 {
1144 dwErrorCode = ERROR_SPL_NO_ADDJOB;
1145 goto Cleanup;
1146 }
1147
1148 // Construct the full path to the spool file.
1149 GetJobFilePath(L"SPL", dwJobID, wszFullPath);
1150
1151 // Check if it exists.
1152 dwAttributes = GetFileAttributesW(wszFullPath);
1154 {
1155 dwErrorCode = ERROR_SPOOL_FILE_NOT_FOUND;
1156 goto Cleanup;
1157 }
1158
1159 // Spooling is finished at this point.
1160 pJob->dwStatus &= ~JOB_STATUS_SPOOLING;
1161
1162 // Write the job data into the shadow file.
1163 wcscpy(wcsrchr(wszFullPath, L'.'), L".SHD");
1164 WriteJobShadowFile(wszFullPath, pJob);
1165
1166 // Create the thread for performing the printing process.
1168 if (!hThread)
1169 {
1170 dwErrorCode = GetLastError();
1171 ERR("CreateThread failed with error %lu!\n", dwErrorCode);
1172 goto Cleanup;
1173 }
1174
1175 // We don't need the thread handle. Keeping it open blocks the thread from terminating.
1177
1178 // ScheduleJob has done its job. The rest happens inside the thread.
1179 dwErrorCode = ERROR_SUCCESS;
1180
1181Cleanup:
1182 SetLastError(dwErrorCode);
1183 return (dwErrorCode == ERROR_SUCCESS);
1184}
1185
1188{
1189 DWORD cbFileSize;
1190 DWORD cbRead;
1192 PLOCAL_JOB pJob;
1193 PLOCAL_JOB pReturnValue = NULL;
1194 PLOCAL_PRINTER pPrinter;
1195 PLOCAL_PRINT_PROCESSOR pPrintProcessor;
1196 PSHD_HEADER pShadowFile = NULL;
1197 PWSTR pwszPrinterName;
1198 PWSTR pwszPrintProcessor;
1199
1200 TRACE("ReadJobShadowFile(%S)\n", pwszFilePath);
1201
1202 // Try to open the file.
1205 {
1206 ERR("CreateFileW failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
1207 goto Cleanup;
1208 }
1209
1210 // Get its file size (small enough for a single DWORD) and allocate memory for all of it.
1211 cbFileSize = GetFileSize(hFile, NULL);
1212 pShadowFile = DllAllocSplMem(cbFileSize);
1213 if (!pShadowFile)
1214 {
1215 ERR("DllAllocSplMem failed for file \"%S\"!\n", pwszFilePath);
1216 goto Cleanup;
1217 }
1218
1219 // Read the entire file.
1220 if (!ReadFile(hFile, pShadowFile, cbFileSize, &cbRead, NULL))
1221 {
1222 ERR("ReadFile failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
1223 goto Cleanup;
1224 }
1225
1226 // Check signature and header size.
1227 if (pShadowFile->dwSignature != SHD_WIN2003_SIGNATURE || pShadowFile->cbHeader != sizeof(SHD_HEADER))
1228 {
1229 ERR("Signature or Header Size mismatch for file \"%S\"!\n", pwszFilePath);
1230 goto Cleanup;
1231 }
1232
1233 // Retrieve the associated printer from the list.
1234 pwszPrinterName = (PWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offPrinterName);
1235 pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL);
1236 if (!pPrinter)
1237 {
1238 ERR("Shadow file \"%S\" references a non-existing printer \"%S\"!\n", pwszFilePath, pwszPrinterName);
1239 goto Cleanup;
1240 }
1241
1242 // Retrieve the associated Print Processor from the list.
1243 pwszPrintProcessor = (PWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offPrintProcessor);
1244 pPrintProcessor = FindPrintProcessor(pwszPrintProcessor);
1245 if (!pPrintProcessor)
1246 {
1247 ERR("Shadow file \"%S\" references a non-existing Print Processor \"%S\"!\n", pwszFilePath, pwszPrintProcessor);
1248 goto Cleanup;
1249 }
1250
1251 // Create a new job structure and copy over the relevant fields.
1252 pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
1253 if (!pJob)
1254 {
1255 ERR("DllAllocSplMem failed for file \"%S\"!\n", pwszFilePath);
1256 goto Cleanup;
1257 }
1258
1259 pJob->dwJobID = pShadowFile->dwJobID;
1260 pJob->dwPriority = pShadowFile->dwPriority;
1261 pJob->dwStartTime = pShadowFile->dwStartTime;
1262 pJob->dwTotalPages = pShadowFile->dwTotalPages;
1263 pJob->dwUntilTime = pShadowFile->dwUntilTime;
1264 pJob->pPrinter = pPrinter;
1265 pJob->pPrintProcessor = pPrintProcessor;
1266 pJob->pDevMode = DuplicateDevMode((PDEVMODEW)((ULONG_PTR)pShadowFile + pShadowFile->offDevMode));
1267 pJob->pwszDatatype = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDatatype));
1268 pJob->pwszMachineName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offMachineName));
1269 CopyMemory(&pJob->stSubmitted, &pShadowFile->stSubmitted, sizeof(SYSTEMTIME));
1270
1271 // Copy the optional values.
1272 if (pShadowFile->offDocumentName)
1273 pJob->pwszDocumentName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDocumentName));
1274
1275 if (pShadowFile->offNotifyName)
1276 pJob->pwszNotifyName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offNotifyName));
1277
1278 if (pShadowFile->offPrintProcessorParameters)
1280
1281 if (pShadowFile->offUserName)
1282 pJob->pwszUserName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offUserName));
1283
1284 // Jobs read from shadow files were always added using AddJob.
1285 pJob->bAddedJob = TRUE;
1286
1287 pReturnValue = pJob;
1288
1289Cleanup:
1290 if (pShadowFile)
1291 DllFreeSplMem(pShadowFile);
1292
1295
1296 return pReturnValue;
1297}
1298
1299BOOL
1300WriteJobShadowFile(PWSTR pwszFilePath, const PLOCAL_JOB pJob)
1301{
1302 BOOL bReturnValue = FALSE;
1303 DWORD cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR);
1304 DWORD cbDevMode = pJob->pDevMode->dmSize + pJob->pDevMode->dmDriverExtra;
1305 DWORD cbDocumentName = 0;
1306 DWORD cbFileSize;
1307 DWORD cbMachineName = (wcslen(pJob->pwszMachineName) + 1) * sizeof(WCHAR);
1308 DWORD cbNotifyName = 0;
1309 DWORD cbPrinterDriver = (wcslen(pJob->pPrinter->pwszPrinterDriver) + 1) * sizeof(WCHAR);
1310 DWORD cbPrinterName = (wcslen(pJob->pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR);
1311 DWORD cbPrintProcessor = (wcslen(pJob->pPrintProcessor->pwszName) + 1) * sizeof(WCHAR);
1312 DWORD cbPrintProcessorParameters = 0;
1313 DWORD cbUserName = 0;
1314 DWORD cbWritten;
1315 DWORD dwCurrentOffset;
1316 HANDLE hSHDFile = INVALID_HANDLE_VALUE;
1317 HANDLE hSPLFile = INVALID_HANDLE_VALUE;
1318 PSHD_HEADER pShadowFile = NULL;
1319
1320 TRACE("WriteJobShadowFile(%S, %p)\n", pwszFilePath, pJob);
1321
1322 // Try to open the SHD file.
1323 hSHDFile = CreateFileW(pwszFilePath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
1324 if (hSHDFile == INVALID_HANDLE_VALUE)
1325 {
1326 ERR("CreateFileW failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
1327 goto Cleanup;
1328 }
1329
1330 // Calculate the lengths of the optional values and the total size of the shadow file.
1331 if (pJob->pwszDocumentName)
1332 cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR);
1333
1334 if (pJob->pwszNotifyName)
1335 cbNotifyName = (wcslen(pJob->pwszNotifyName) + 1) * sizeof(WCHAR);
1336
1338 cbPrintProcessorParameters = (wcslen(pJob->pwszPrintProcessorParameters) + 1) * sizeof(WCHAR);
1339
1340 if (pJob->pwszUserName)
1341 cbUserName = (wcslen(pJob->pwszUserName) + 1) * sizeof(WCHAR);
1342
1343 cbFileSize = sizeof(SHD_HEADER) + cbDatatype + cbDocumentName + cbDevMode + cbMachineName + cbNotifyName + cbPrinterDriver + cbPrinterName + cbPrintProcessor + cbPrintProcessorParameters + cbUserName;
1344
1345 // Allocate memory for it.
1346 pShadowFile = DllAllocSplMem(cbFileSize);
1347 if (!pShadowFile)
1348 {
1349 ERR("DllAllocSplMem failed for file \"%S\"!\n", pwszFilePath);
1350 goto Cleanup;
1351 }
1352
1353 // Fill out the shadow file header information.
1354 pShadowFile->dwSignature = SHD_WIN2003_SIGNATURE;
1355 pShadowFile->cbHeader = sizeof(SHD_HEADER);
1356
1357 // Copy the values.
1358 pShadowFile->dwJobID = pJob->dwJobID;
1359 pShadowFile->dwPriority = pJob->dwPriority;
1360 pShadowFile->dwStartTime = pJob->dwStartTime;
1361 pShadowFile->dwTotalPages = pJob->dwTotalPages;
1362 pShadowFile->dwUntilTime = pJob->dwUntilTime;
1363 CopyMemory(&pShadowFile->stSubmitted, &pJob->stSubmitted, sizeof(SYSTEMTIME));
1364
1365 // Determine the file size of the .SPL file
1366 wcscpy(wcsrchr(pwszFilePath, L'.'), L".SPL");
1368 if (hSPLFile != INVALID_HANDLE_VALUE)
1369 pShadowFile->dwSPLSize = GetFileSize(hSPLFile, NULL);
1370
1371 // Add the extra values that are stored as offsets in the shadow file.
1372 // The first value begins right after the shadow file header.
1373 dwCurrentOffset = sizeof(SHD_HEADER);
1374
1375 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszDatatype, cbDatatype);
1376 pShadowFile->offDatatype = dwCurrentOffset;
1377 dwCurrentOffset += cbDatatype;
1378
1379 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pDevMode, cbDevMode);
1380 pShadowFile->offDevMode = dwCurrentOffset;
1381 dwCurrentOffset += cbDevMode;
1382
1383 // offDriverName is only written, but automatically determined through offPrinterName when reading.
1384 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pPrinter->pwszPrinterDriver, cbPrinterDriver);
1385 pShadowFile->offDriverName = dwCurrentOffset;
1386 dwCurrentOffset += cbPrinterDriver;
1387
1388 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszMachineName, cbMachineName);
1389 pShadowFile->offMachineName = dwCurrentOffset;
1390 dwCurrentOffset += cbMachineName;
1391
1392 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pPrinter->pwszPrinterName, cbPrinterName);
1393 pShadowFile->offPrinterName = dwCurrentOffset;
1394 dwCurrentOffset += cbPrinterName;
1395
1396 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pPrintProcessor->pwszName, cbPrintProcessor);
1397 pShadowFile->offPrintProcessor = dwCurrentOffset;
1398 dwCurrentOffset += cbPrintProcessor;
1399
1400 // Copy the optional values.
1401 if (cbDocumentName)
1402 {
1403 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszDocumentName, cbDocumentName);
1404 pShadowFile->offDocumentName = dwCurrentOffset;
1405 dwCurrentOffset += cbDocumentName;
1406 }
1407
1408 if (cbNotifyName)
1409 {
1410 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszNotifyName, cbNotifyName);
1411 pShadowFile->offNotifyName = dwCurrentOffset;
1412 dwCurrentOffset += cbNotifyName;
1413 }
1414
1415 if (cbPrintProcessorParameters)
1416 {
1417 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszPrintProcessorParameters, cbPrintProcessorParameters);
1418 pShadowFile->offPrintProcessorParameters = dwCurrentOffset;
1419 dwCurrentOffset += cbPrintProcessorParameters;
1420 }
1421
1422 if (cbUserName)
1423 {
1424 CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszUserName, cbUserName);
1425 pShadowFile->offUserName = dwCurrentOffset;
1426 dwCurrentOffset += cbUserName;
1427 }
1428
1429 // Write the file.
1430 if (!WriteFile(hSHDFile, pShadowFile, cbFileSize, &cbWritten, NULL))
1431 {
1432 ERR("WriteFile failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
1433 goto Cleanup;
1434 }
1435
1436 bReturnValue = TRUE;
1437
1438Cleanup:
1439 if (pShadowFile)
1440 DllFreeSplMem(pShadowFile);
1441
1442 if (hSHDFile != INVALID_HANDLE_VALUE)
1443 CloseHandle(hSHDFile);
1444
1445 if (hSPLFile != INVALID_HANDLE_VALUE)
1446 CloseHandle(hSPLFile);
1447
1448 return bReturnValue;
1449}
1450
1451void
1453{
1454 PWSTR pwszSHDFile;
1455
1456 TRACE("FreeJob(%p)\n", pJob);
1457
1458 // Remove the Job from both Job Lists.
1459 DeleteElementSkiplist(&pJob->pPrinter->JobList, pJob);
1461
1462 // Try to delete the corresponding .SHD file.
1463 pwszSHDFile = DllAllocSplMem(GetJobFilePath(L"SHD", 0, NULL));
1464 if (pwszSHDFile && GetJobFilePath(L"SHD", pJob->dwJobID, pwszSHDFile))
1465 DeleteFileW(pwszSHDFile);
1466
1467 // Free memory for the mandatory fields.
1468 DllFreeSplMem(pJob->pDevMode);
1474
1475 // Free memory for the optional fields if they are present.
1476 if (pJob->pwszOutputFile)
1478
1481
1482 if (pJob->pwszStatus)
1484
1485 // Finally free the job structure itself.
1486 DllFreeSplMem(pJob);
1487}
static LPWSTR pUserName
PBYTE WINAPI PackStrings(PCWSTR *pSource, PBYTE pDest, const DWORD *DestOffsets, PBYTE pEnd)
Definition: tools.c:39
#define FIXME(fmt,...)
Definition: debug.h:111
#define ERR(fmt,...)
Definition: debug.h:110
Definition: ehthrow.cxx:93
Definition: ehthrow.cxx:54
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#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
BOOL WINAPI GetUserNameW(LPWSTR lpszName, LPDWORD lpSize)
Definition: misc.c:291
#define CloseHandle
Definition: compat.h:739
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define wcsrchr
Definition: compat.h:16
#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 wcsicmp
Definition: compat.h:15
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName)
Definition: fileinfo.c:652
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
Definition: fileinfo.c:331
HANDLE WINAPI FindFirstFileW(IN LPCWSTR lpFileName, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:320
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
BOOL WINAPI FindNextFileW(IN HANDLE hFindFile, OUT LPWIN32_FIND_DATAW lpFindFileData)
Definition: find.c:382
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
VOID WINAPI GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime)
Definition: time.c:128
BOOL WINAPI SystemTimeToFileTime(IN CONST SYSTEMTIME *lpSystemTime, OUT LPFILETIME lpFileTime)
Definition: time.c:158
LONG WINAPI CompareFileTime(IN CONST FILETIME *lpFileTime1, IN CONST FILETIME *lpFileTime2)
Definition: time.c:106
VOID WINAPI GetSystemTime(OUT LPSYSTEMTIME lpSystemTime)
Definition: time.c:327
#define swprintf
Definition: precomp.h:40
static const WCHAR Cleanup[]
Definition: register.c:80
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
__in WDFDMATRANSACTION __out NTSTATUS * pStatus
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
#define CREATE_ALWAYS
Definition: disk.h:72
_In_ HANDLE hFile
Definition: mswsock.h:90
HANDLE hThread
Definition: wizard.c:28
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define DWORD
Definition: nt_native.h:44
#define GENERIC_WRITE
Definition: nt_native.h:90
#define MAXDWORD
#define L(x)
Definition: ntvdm.h:50
BYTE * PBYTE
Definition: pedump.c:66
DWORD * PDWORD
Definition: pedump.c:68
static DWORD _LocalSetJobLevel2(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PJOB_INFO_2W pJobInfo)
Definition: jobs.c:818
BOOL WINAPI LocalGetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded)
Definition: jobs.c:655
BOOL InitializeGlobalJobList(void)
Definition: jobs.c:161
SKIPLIST GlobalJobList
Definition: jobs.c:11
DWORD WINAPI CreateJob(PLOCAL_PRINTER_HANDLE pPrinterHandle)
Definition: jobs.c:257
BOOL WINAPI LocalScheduleJob(HANDLE hPrinter, DWORD dwJobID)
Definition: jobs.c:1112
static DWORD dwJobInfo2Offsets[]
Definition: jobs.c:27
static void _LocalGetJobLevel1(PLOCAL_JOB pJob, PJOB_INFO_1W *ppJobInfo, PBYTE *ppJobInfoEnd, PDWORD pcbNeeded)
Definition: jobs.c:450
BOOL WINAPI LocalSetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
Definition: jobs.c:949
void InitializePrinterJobList(PLOCAL_PRINTER pPrinter)
Definition: jobs.c:247
BOOL WINAPI LocalAddJob(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded)
Definition: jobs.c:380
static int WINAPI _GlobalJobListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct)
Definition: jobs.c:100
BOOL WINAPI LocalEnumJobs(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned)
Definition: jobs.c:1022
static BOOL _GetNextJobID(PDWORD dwJobID)
Definition: jobs.c:73
static int WINAPI _PrinterJobListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct)
Definition: jobs.c:115
static DWORD _dwLastJobID
Definition: jobs.c:14
static void _LocalGetJobLevel2(PLOCAL_JOB pJob, PJOB_INFO_2W *ppJobInfo, PBYTE *ppJobInfoEnd, PDWORD pcbNeeded)
Definition: jobs.c:524
DWORD GetJobFilePath(PCWSTR pwszExtension, DWORD dwJobID, PWSTR pwszOutput)
Definition: jobs.c:146
BOOL WriteJobShadowFile(PWSTR pwszFilePath, const PLOCAL_JOB pJob)
Definition: jobs.c:1300
static DWORD dwJobInfo1Offsets[]
Definition: jobs.c:17
static DWORD _LocalSetJobLevel1(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PJOB_INFO_1W pJobInfo)
Definition: jobs.c:721
void FreeJob(PLOCAL_JOB pJob)
Definition: jobs.c:1452
PLOCAL_JOB ReadJobShadowFile(PCWSTR pwszFilePath)
Definition: jobs.c:1187
static __inline BOOL _EqualStrings(PCWSTR pwszA, PCWSTR pwszB)
Definition: jobs.c:58
RPC_STATUS WINAPI RpcBindingFree(RPC_BINDING_HANDLE *Binding)
Definition: rpc_binding.c:787
RPC_STATUS WINAPI RpcStringBindingParseW(RPC_WSTR StringBinding, RPC_WSTR *ObjUuid, RPC_WSTR *Protseq, RPC_WSTR *NetworkAddr, RPC_WSTR *Endpoint, RPC_WSTR *Options)
Definition: rpc_binding.c:676
RPCRTAPI RPC_STATUS RPC_ENTRY RpcBindingServerFromClient(RPC_BINDING_HANDLE ClientBinding, RPC_BINDING_HANDLE *ServerBinding)
Definition: rpc_binding.c:1646
RPC_STATUS WINAPI RpcBindingToStringBindingW(RPC_BINDING_HANDLE Binding, RPC_WSTR *StringBinding)
Definition: rpc_binding.c:947
unsigned short * RPC_WSTR
Definition: rpcdce.h:46
#define RPC_S_OK
Definition: rpcnterr.h:22
RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR *String)
Definition: rpcrt4_main.c:175
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
BOOL InsertTailElementSkiplist(PSKIPLIST Skiplist, PVOID Element)
Definition: skiplist.c:308
PVOID LookupElementSkiplist(PSKIPLIST Skiplist, PVOID Element, PDWORD ElementIndex)
Definition: skiplist.c:357
PSKIPLIST_NODE LookupNodeByIndexSkiplist(PSKIPLIST Skiplist, DWORD ElementIndex)
Definition: skiplist.c:412
BOOL InsertElementSkiplist(PSKIPLIST Skiplist, PVOID Element)
Definition: skiplist.c:250
PVOID DeleteElementSkiplist(PSKIPLIST Skiplist, PVOID Element)
Definition: skiplist.c:146
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:68
#define TRACE(s)
Definition: solgame.cpp:4
#define UNLEN
Definition: sspi.c:28
Definition: shell.h:41
DWORD dwHighDateTime
Definition: mapidefs.h:66
DWORD dwLowDateTime
Definition: mapidefs.h:65
DWORD Priority
Definition: winspool.h:257
LPWSTR pStatus
Definition: winspool.h:255
LPWSTR pDocument
Definition: winspool.h:253
LPWSTR pUserName
Definition: winspool.h:252
DWORD Status
Definition: winspool.h:256
LPWSTR pDatatype
Definition: winspool.h:254
LPWSTR pParameters
Definition: winspool.h:303
LPWSTR pPrintProcessor
Definition: winspool.h:302
LPWSTR pDocument
Definition: winspool.h:299
LPWSTR pDatatype
Definition: winspool.h:301
DWORD Status
Definition: winspool.h:308
LPWSTR pUserName
Definition: winspool.h:298
LPWSTR pNotifyName
Definition: winspool.h:300
DWORD Priority
Definition: winspool.h:309
LPWSTR pStatus
Definition: winspool.h:306
enum _LOCAL_HANDLE::@5124 HandleType
PVOID pSpecificHandle
Definition: precomp.h:208
DWORD dwStatus
Definition: precomp.h:159
DWORD dwPriority
Definition: precomp.h:146
HANDLE hPrintProcessor
Definition: precomp.h:143
PWSTR pwszStatus
Definition: precomp.h:154
DWORD dwPagesPrinted
Definition: precomp.h:156
SYSTEMTIME stSubmitted
Definition: precomp.h:147
DWORD dwStartTime
Definition: precomp.h:157
DWORD dwJobID
Definition: precomp.h:140
PLOCAL_PRINTER pPrinter
Definition: precomp.h:144
PWSTR pwszMachineName
Definition: precomp.h:160
PLOCAL_PRINT_PROCESSOR pPrintProcessor
Definition: precomp.h:145
DWORD dwTotalPages
Definition: precomp.h:155
BOOL bAddedJob
Definition: precomp.h:142
PDEVMODEW pDevMode
Definition: precomp.h:161
PWSTR pwszDatatype
Definition: precomp.h:151
PWSTR pwszUserName
Definition: precomp.h:148
PWSTR pwszNotifyName
Definition: precomp.h:149
PWSTR pwszOutputFile
Definition: precomp.h:152
PWSTR pwszPrintProcessorParameters
Definition: precomp.h:153
DWORD dwUntilTime
Definition: precomp.h:158
PWSTR pwszDocumentName
Definition: precomp.h:150
PLOCAL_PRINTER pPrinter
Definition: precomp.h:171
PLOCAL_JOB pJob
Definition: precomp.h:172
PDEVMODEW pDevMode
Definition: precomp.h:174
PWSTR pwszPrinterName
Definition: precomp.h:119
PWSTR pwszPrinterDriver
Definition: precomp.h:124
DWORD dwAttributes
Definition: precomp.h:121
PLOCAL_PRINT_PROCESSOR pPrintProcessor
Definition: precomp.h:128
SKIPLIST JobList
Definition: precomp.h:130
PControlPrintProcessor pfnControlPrintProcessor
Definition: precomp.h:105
DWORD dwTotalPages
Definition: precomp.h:238
DWORD dwJobID
Definition: precomp.h:222
DWORD offUserName
Definition: precomp.h:224
DWORD offMachineName
Definition: precomp.h:244
DWORD offDocumentName
Definition: precomp.h:226
DWORD offDriverName
Definition: precomp.h:229
DWORD offDatatype
Definition: precomp.h:232
DWORD dwPriority
Definition: precomp.h:223
DWORD offPrinterName
Definition: precomp.h:228
DWORD dwSPLSize
Definition: precomp.h:245
DWORD offPrintProcessor
Definition: precomp.h:231
DWORD cbHeader
Definition: precomp.h:219
DWORD offPrintProcessorParameters
Definition: precomp.h:233
DWORD dwSignature
Definition: precomp.h:218
DWORD offDevMode
Definition: precomp.h:230
DWORD dwUntilTime
Definition: precomp.h:236
DWORD dwStartTime
Definition: precomp.h:235
SYSTEMTIME stSubmitted
Definition: precomp.h:234
DWORD offNotifyName
Definition: precomp.h:225
struct _SKIPLIST_NODE * Next[SKIPLIST_LEVELS]
Definition: skiplist.h:30
PVOID Element
Definition: skiplist.h:31
$ULONG LowPart
Definition: ntbasedef.h:569
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
$ULONG HighPart
Definition: ntbasedef.h:570
WORD dmDriverExtra
Definition: wingdi.h:1621
WORD dmSize
Definition: wingdi.h:1620
TW_UINT32 TW_UINT16 TW_UINT16 TW_MEMREF pData
Definition: twain.h:1830
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
uint32_t * LPDWORD
Definition: typedefs.h:59
uint32_t ULONG_PTR
Definition: typedefs.h:65
DWORD dwAttributes
Definition: vdmdbg.h:34
#define INVALID_FILE_ATTRIBUTES
Definition: vfdcmd.c:23
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
const WCHAR wszDefaultDocumentName[]
Definition: main.c:25
DWORD cchJobDirectory
Definition: main.c:14
WCHAR wszJobDirectory[MAX_PATH]
Definition: main.c:13
struct _SHD_HEADER SHD_HEADER
Definition: precomp.h:65
DWORD WINAPI PrintingThreadProc(PLOCAL_JOB pJob)
#define SHD_WIN2003_SIGNATURE
Definition: precomp.h:42
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)
struct _LOCAL_JOB * PLOCAL_JOB
Definition: precomp.h:57
#define IS_VALID_JOB_ID(ID)
Definition: precomp.h:38
#define IS_VALID_PRIORITY(P)
Definition: precomp.h:39
struct _LOCAL_HANDLE * PLOCAL_HANDLE
Definition: precomp.h:56
SKIPLIST PrinterList
Definition: printers.c:11
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define CopyMemory
Definition: winbase.h:1710
DWORD(WINAPI * LPTHREAD_START_ROUTINE)(LPVOID)
Definition: winbase.h:729
_In_ DWORD _Out_ PDWORD pcbNeeded
Definition: winddi.h:3828
#define WINAPI
Definition: msvc.h:6
#define ERROR_INVALID_DATATYPE
Definition: winerror.h:1111
#define ERROR_INVALID_LEVEL
Definition: winerror.h:196
#define ERROR_UNKNOWN_PRINTPROCESSOR
Definition: winerror.h:1105
#define ERROR_INVALID_ACCESS
Definition: winerror.h:115
#define ERROR_SPOOL_FILE_NOT_FOUND
Definition: winerror.h:1207
#define ERROR_SPL_NO_ADDJOB
Definition: winerror.h:1209
struct _devicemodeW * PDEVMODEW
#define JOB_STATUS_SPOOLING
Definition: winspool.h:341
#define JOB_STATUS_ERROR
Definition: winspool.h:339
#define DEF_PRIORITY
Definition: winspool.h:230
struct _JOB_INFO_1W JOB_INFO_1W
#define JOB_STATUS_PAPEROUT
Definition: winspool.h:344
struct _JOB_INFO_2W JOB_INFO_2W
struct _ADDJOB_INFO_1W ADDJOB_INFO_1W
#define JOB_CONTROL_CANCEL
Definition: winspool.h:332
#define JOB_STATUS_OFFLINE
Definition: winspool.h:343
#define PRINTER_ATTRIBUTE_DIRECT
Definition: winspool.h:209
#define JOB_STATUS_PAUSED
Definition: winspool.h:338
#define JOB_CONTROL_SENT_TO_PRINTER
Definition: winspool.h:335
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:56
_IRQL_requires_same_ _In_ PVOID _In_ PVOID SecondStruct
Definition: rtltypes.h:390
_IRQL_requires_same_ _In_ PVOID FirstStruct
Definition: rtltypes.h:389
__wchar_t WCHAR
Definition: xmlstorage.h:180