ReactOS  0.4.11-dev-791-gf6f1255
printers.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Spooler API
3  * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE: Functions related to Printers and printing
5  * COPYRIGHT: Copyright 2015-2018 Colin Finck (colin@reactos.org)
6  */
7 
8 #include "precomp.h"
9 #include <marshalling/printers.h>
10 
11 // Local Constants
12 
15 static const WCHAR wszWindowsKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
16 static const WCHAR wszDeviceValue[] = L"Device";
17 
18 static DWORD
20 {
21  DWORD cbNeeded;
22  DWORD dwErrorCode;
23  PJOB_INFO_1W pJobInfo1 = NULL;
24 
25  // Create the spool file.
27  if (pHandle->hSPLFile == INVALID_HANDLE_VALUE)
28  {
29  dwErrorCode = GetLastError();
30  ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1->Path, dwErrorCode);
31  goto Cleanup;
32  }
33 
34  // Get the size of the job information.
35  GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded);
37  {
38  dwErrorCode = GetLastError();
39  ERR("GetJobW failed with error %lu!\n", dwErrorCode);
40  goto Cleanup;
41  }
42 
43  // Allocate enough memory for the returned job information.
44  pJobInfo1 = HeapAlloc(hProcessHeap, 0, cbNeeded);
45  if (!pJobInfo1)
46  {
47  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
48  ERR("HeapAlloc failed!\n");
49  goto Cleanup;
50  }
51 
52  // Get the job information.
53  if (!GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, cbNeeded, &cbNeeded))
54  {
55  dwErrorCode = GetLastError();
56  ERR("GetJobW failed with error %lu!\n", dwErrorCode);
57  goto Cleanup;
58  }
59 
60  // Add our document information.
61  if (pDocInfo1->pDatatype)
62  pJobInfo1->pDatatype = pDocInfo1->pDatatype;
63 
64  pJobInfo1->pDocument = pDocInfo1->pDocName;
65 
66  // Set the new job information.
67  if (!SetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0))
68  {
69  dwErrorCode = GetLastError();
70  ERR("SetJobW failed with error %lu!\n", dwErrorCode);
71  goto Cleanup;
72  }
73 
74  // We were successful!
75  pHandle->dwJobID = pAddJobInfo1->JobId;
76  dwErrorCode = ERROR_SUCCESS;
77 
78 Cleanup:
79  if (pJobInfo1)
80  HeapFree(hProcessHeap, 0, pJobInfo1);
81 
82  return dwErrorCode;
83 }
84 
85 static DWORD
87 {
88  DWORD dwErrorCode;
89  WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer;
90 
91  DocInfoContainer.Level = 1;
92  DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1;
93 
95  {
96  dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer, &pHandle->dwJobID);
97  }
99  {
100  dwErrorCode = RpcExceptionCode();
101  ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode);
102  }
103  RpcEndExcept;
104 
105  return dwErrorCode;
106 }
107 
108 BOOL WINAPI
110 {
111  TRACE("AbortPrinter(%p)\n", hPrinter);
113  return FALSE;
114 }
115 
118 {
119  TRACE("AddPrinterA(%s, %lu, %p)\n", pName, Level, pPrinter);
121  return NULL;
122 }
123 
126 {
127  TRACE("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter);
129  return NULL;
130 }
131 
132 BOOL WINAPI
134 {
135  DWORD dwErrorCode;
136  PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
137 
138  TRACE("ClosePrinter(%p)\n", hPrinter);
139 
140  // Sanity checks.
141  if (!pHandle)
142  {
143  dwErrorCode = ERROR_INVALID_HANDLE;
144  goto Cleanup;
145  }
146 
147  // Do the RPC call.
149  {
150  dwErrorCode = _RpcClosePrinter(&pHandle->hPrinter);
151  }
153  {
154  dwErrorCode = RpcExceptionCode();
155  ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode);
156  }
157  RpcEndExcept;
158 
159  // Close any open file handle.
160  if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
161  CloseHandle(pHandle->hSPLFile);
162 
163  // Free the memory for the handle.
164  HeapFree(hProcessHeap, 0, pHandle);
165 
166 Cleanup:
167  SetLastError(dwErrorCode);
168  return (dwErrorCode == ERROR_SUCCESS);
169 }
170 
171 BOOL WINAPI
173 {
174  TRACE("DeletePrinter(%p)\n", hPrinter);
176  return FALSE;
177 }
178 
180 DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
181 {
182  TRACE("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
184  return 0;
185 }
186 
188 DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
189 {
190  TRACE("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
192  return 0;
193 }
194 
195 LONG WINAPI
196 DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
197 {
198  TRACE("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
200  return -1;
201 }
202 
203 LONG WINAPI
204 DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
205 {
206  TRACE("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
208  return -1;
209 }
210 
211 BOOL WINAPI
213 {
214  DWORD dwErrorCode;
215  PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
216 
217  TRACE("EndDocPrinter(%p)\n", hPrinter);
218 
219  // Sanity checks.
220  if (!pHandle)
221  {
222  dwErrorCode = ERROR_INVALID_HANDLE;
223  goto Cleanup;
224  }
225 
226  if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
227  {
228  // For spooled jobs, the document is finished by calling _RpcScheduleJob.
230  {
231  dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID);
232  }
234  {
235  dwErrorCode = RpcExceptionCode();
236  ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
237  }
238  RpcEndExcept;
239 
240  // Close the spool file handle.
241  CloseHandle(pHandle->hSPLFile);
242  }
243  else
244  {
245  // In all other cases, just call _RpcEndDocPrinter.
247  {
248  dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter);
249  }
251  {
252  dwErrorCode = RpcExceptionCode();
253  ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode);
254  }
255  RpcEndExcept;
256  }
257 
258  // A new document can now be started again.
259  pHandle->bStartedDoc = FALSE;
260 
261 Cleanup:
262  SetLastError(dwErrorCode);
263  return (dwErrorCode == ERROR_SUCCESS);
264 }
265 
266 BOOL WINAPI
268 {
269  DWORD dwErrorCode;
270  PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
271 
272  TRACE("EndPagePrinter(%p)\n", hPrinter);
273 
274  // Sanity checks.
275  if (!pHandle)
276  {
277  dwErrorCode = ERROR_INVALID_HANDLE;
278  goto Cleanup;
279  }
280 
281  if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
282  {
283  // For spooled jobs, we don't need to do anything.
284  dwErrorCode = ERROR_SUCCESS;
285  }
286  else
287  {
288  // In all other cases, just call _RpcEndPagePrinter.
290  {
291  dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter);
292  }
294  {
295  dwErrorCode = RpcExceptionCode();
296  ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode);
297  }
298  RpcEndExcept;
299  }
300 
301 Cleanup:
302  SetLastError(dwErrorCode);
303  return (dwErrorCode == ERROR_SUCCESS);
304 }
305 
306 BOOL WINAPI
308 {
309  TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
310  return FALSE;
311 }
312 
313 BOOL WINAPI
315 {
316  DWORD dwErrorCode;
317 
318  TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
319 
320  // Dismiss invalid levels already at this point.
321  if (Level == 3 || Level > 5)
322  {
323  dwErrorCode = ERROR_INVALID_LEVEL;
324  goto Cleanup;
325  }
326 
327  if (cbBuf && pPrinterEnum)
328  ZeroMemory(pPrinterEnum, cbBuf);
329 
330  // Do the RPC call
332  {
333  dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
334  }
336  {
337  dwErrorCode = RpcExceptionCode();
338  ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
339  }
340  RpcEndExcept;
341 
342  if (dwErrorCode == ERROR_SUCCESS)
343  {
344  // Replace relative offset addresses in the output by absolute pointers.
345  ASSERT(Level <= 9);
346  MarshallUpStructuresArray(cbBuf, pPrinterEnum, *pcReturned, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
347  }
348 
349 Cleanup:
350  SetLastError(dwErrorCode);
351  return (dwErrorCode == ERROR_SUCCESS);
352 }
353 
354 BOOL WINAPI
355 FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep)
356 {
357  TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter, pBuf, cbBuf, pcWritten, cSleep);
359  return FALSE;
360 }
361 
362 BOOL WINAPI
363 GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
364 {
365  DWORD dwErrorCode;
366  PWSTR pwszBuffer = NULL;
367 
368  TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer, pcchBuffer);
369 
370  // Sanity check.
371  if (!pcchBuffer)
372  {
373  dwErrorCode = ERROR_INVALID_PARAMETER;
374  goto Cleanup;
375  }
376 
377  // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
378  if (pszBuffer && *pcchBuffer)
379  {
380  pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR));
381  if (!pwszBuffer)
382  {
383  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
384  ERR("HeapAlloc failed!\n");
385  goto Cleanup;
386  }
387  }
388 
389  if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer))
390  {
391  dwErrorCode = GetLastError();
392  goto Cleanup;
393  }
394 
395  // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
396  WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, *pcchBuffer, NULL, NULL);
397 
398  dwErrorCode = ERROR_SUCCESS;
399 
400 Cleanup:
401  if (pwszBuffer)
402  HeapFree(hProcessHeap, 0, pwszBuffer);
403 
404  SetLastError(dwErrorCode);
405  return (dwErrorCode == ERROR_SUCCESS);
406 }
407 
408 BOOL WINAPI
409 GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
410 {
411  DWORD cbNeeded;
412  DWORD cchInputBuffer;
413  DWORD dwErrorCode;
414  HKEY hWindowsKey = NULL;
415  PWSTR pwszDevice = NULL;
416  PWSTR pwszComma;
417 
418  TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer, pcchBuffer);
419 
420  // Sanity check.
421  if (!pcchBuffer)
422  {
423  dwErrorCode = ERROR_INVALID_PARAMETER;
424  goto Cleanup;
425  }
426 
427  cchInputBuffer = *pcchBuffer;
428 
429  // Open the registry key where the default printer for the current user is stored.
430  dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey);
431  if (dwErrorCode != ERROR_SUCCESS)
432  {
433  ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
434  goto Cleanup;
435  }
436 
437  // Determine the size of the required buffer.
438  dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded);
439  if (dwErrorCode != ERROR_SUCCESS)
440  {
441  ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
442  goto Cleanup;
443  }
444 
445  // Allocate it.
446  pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded);
447  if (!pwszDevice)
448  {
449  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
450  ERR("HeapAlloc failed!\n");
451  goto Cleanup;
452  }
453 
454  // Now get the actual value.
455  dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded);
456  if (dwErrorCode != ERROR_SUCCESS)
457  {
458  ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
459  goto Cleanup;
460  }
461 
462  // We get a string "<Printer Name>,winspool,<Port>:".
463  // Extract the printer name from it.
464  pwszComma = wcschr(pwszDevice, L',');
465  if (!pwszComma)
466  {
467  ERR("Found no or invalid default printer: %S!\n", pwszDevice);
468  dwErrorCode = ERROR_INVALID_NAME;
469  goto Cleanup;
470  }
471 
472  // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
473  *pcchBuffer = pwszComma - pwszDevice + 1;
474 
475  // Check if the supplied buffer is large enough.
476  if (cchInputBuffer < *pcchBuffer)
477  {
478  dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
479  goto Cleanup;
480  }
481 
482  // Copy the default printer.
483  *pwszComma = 0;
484  CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR));
485 
486  dwErrorCode = ERROR_SUCCESS;
487 
488 Cleanup:
489  if (hWindowsKey)
490  RegCloseKey(hWindowsKey);
491 
492  if (pwszDevice)
493  HeapFree(hProcessHeap, 0, pwszDevice);
494 
495  SetLastError(dwErrorCode);
496  return (dwErrorCode == ERROR_SUCCESS);
497 }
498 
499 BOOL WINAPI
501 {
502  TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
503  return FALSE;
504 }
505 
506 BOOL WINAPI
507 GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
508 {
509  TRACE("GetPrinterDriverA(%p, %s, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
510  return FALSE;
511 }
512 
513 BOOL WINAPI
514 GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
515 {
516  TRACE("GetPrinterDriverW(%p, %S, %lu, %p, %lu, %p)\n", hPrinter, pEnvironment, Level, pDriverInfo, cbBuf, pcbNeeded);
517  return FALSE;
518 }
519 
520 BOOL WINAPI
522 {
523  DWORD dwErrorCode;
524  PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
525 
526  TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
527 
528  // Sanity checks.
529  if (!pHandle)
530  {
531  dwErrorCode = ERROR_INVALID_HANDLE;
532  goto Cleanup;
533  }
534 
535  // Dismiss invalid levels already at this point.
536  if (Level > 9)
537  {
538  dwErrorCode = ERROR_INVALID_LEVEL;
539  goto Cleanup;
540  }
541 
542  if (cbBuf && pPrinter)
543  ZeroMemory(pPrinter, cbBuf);
544 
545  // Do the RPC call
547  {
548  dwErrorCode = _RpcGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
549  }
551  {
552  dwErrorCode = RpcExceptionCode();
553  ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode);
554  }
555  RpcEndExcept;
556 
557  if (dwErrorCode == ERROR_SUCCESS)
558  {
559  // Replace relative offset addresses in the output by absolute pointers.
560  ASSERT(Level <= 9);
561  MarshallUpStructure(cbBuf, pPrinter, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
562  }
563 
564 Cleanup:
565  SetLastError(dwErrorCode);
566  return (dwErrorCode == ERROR_SUCCESS);
567 }
568 
569 BOOL WINAPI
570 OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
571 {
572  BOOL bReturnValue = FALSE;
573  DWORD cch;
574  PWSTR pwszPrinterName = NULL;
575  PRINTER_DEFAULTSW wDefault = { 0 };
576 
577  TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName, phPrinter, pDefault);
578 
579  if (pPrinterName)
580  {
581  // Convert pPrinterName to a Unicode string pwszPrinterName
582  cch = strlen(pPrinterName);
583 
584  pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
585  if (!pwszPrinterName)
586  {
588  ERR("HeapAlloc failed!\n");
589  goto Cleanup;
590  }
591 
592  MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, cch + 1);
593  }
594 
595  if (pDefault)
596  {
597  wDefault.DesiredAccess = pDefault->DesiredAccess;
598 
599  if (pDefault->pDatatype)
600  {
601  // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
602  cch = strlen(pDefault->pDatatype);
603 
604  wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
605  if (!wDefault.pDatatype)
606  {
608  ERR("HeapAlloc failed!\n");
609  goto Cleanup;
610  }
611 
612  MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, wDefault.pDatatype, cch + 1);
613  }
614 
615  if (pDefault->pDevMode)
616  wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode);
617  }
618 
619  bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
620 
621 Cleanup:
622  if (wDefault.pDatatype)
623  HeapFree(hProcessHeap, 0, wDefault.pDatatype);
624 
625  if (wDefault.pDevMode)
626  HeapFree(hProcessHeap, 0, wDefault.pDevMode);
627 
628  if (pwszPrinterName)
629  HeapFree(hProcessHeap, 0, pwszPrinterName);
630 
631  return bReturnValue;
632 }
633 
634 BOOL WINAPI
635 OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
636 {
637  DWORD dwErrorCode;
638  HANDLE hPrinter;
639  PSPOOLER_HANDLE pHandle;
640  PWSTR pDatatype = NULL;
641  WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 };
642  ACCESS_MASK AccessRequired = 0;
643 
644  TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName, phPrinter, pDefault);
645 
646  // Sanity check
647  if (!phPrinter)
648  {
649  dwErrorCode = ERROR_INVALID_PARAMETER;
650  goto Cleanup;
651  }
652 
653  // Prepare the additional parameters in the format required by _RpcOpenPrinter
654  if (pDefault)
655  {
656  pDatatype = pDefault->pDatatype;
657  DevModeContainer.cbBuf = sizeof(DEVMODEW);
658  DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
659  AccessRequired = pDefault->DesiredAccess;
660  }
661 
662  // Do the RPC call
664  {
665  dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired);
666  }
668  {
669  dwErrorCode = RpcExceptionCode();
670  ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
671  }
672  RpcEndExcept;
673 
674  if (dwErrorCode == ERROR_SUCCESS)
675  {
676  // Create a new SPOOLER_HANDLE structure.
678  if (!pHandle)
679  {
680  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
681  ERR("HeapAlloc failed!\n");
682  goto Cleanup;
683  }
684 
685  pHandle->hPrinter = hPrinter;
686  pHandle->hSPLFile = INVALID_HANDLE_VALUE;
687 
688  // Return it as phPrinter.
689  *phPrinter = (HANDLE)pHandle;
690  }
691 
692 Cleanup:
693  SetLastError(dwErrorCode);
694  return (dwErrorCode == ERROR_SUCCESS);
695 }
696 
697 BOOL WINAPI
698 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
699 {
700  DWORD dwErrorCode;
701  PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
702 
703  TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pNoBytesRead);
704 
705  // Sanity checks.
706  if (!pHandle)
707  {
708  dwErrorCode = ERROR_INVALID_HANDLE;
709  goto Cleanup;
710  }
711 
712  // Do the RPC call
714  {
715  dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
716  }
718  {
719  dwErrorCode = RpcExceptionCode();
720  ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode);
721  }
722  RpcEndExcept;
723 
724 Cleanup:
725  SetLastError(dwErrorCode);
726  return (dwErrorCode == ERROR_SUCCESS);
727 }
728 
729 BOOL WINAPI
731 {
732  TRACE("ResetPrinterA(%p, %p)\n", hPrinter, pDefault);
734  return FALSE;
735 }
736 
737 BOOL WINAPI
739 {
740  TRACE("ResetPrinterW(%p, %p)\n", hPrinter, pDefault);
742  return FALSE;
743 }
744 
745 BOOL WINAPI
747 {
748  BOOL bReturnValue = FALSE;
749  DWORD cch;
750  PWSTR pwszPrinter = NULL;
751 
752  TRACE("SetDefaultPrinterA(%s)\n", pszPrinter);
753 
754  if (pszPrinter)
755  {
756  // Convert pszPrinter to a Unicode string pwszPrinter
757  cch = strlen(pszPrinter);
758 
759  pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
760  if (!pwszPrinter)
761  {
763  ERR("HeapAlloc failed!\n");
764  goto Cleanup;
765  }
766 
767  MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, pwszPrinter, cch + 1);
768  }
769 
770  bReturnValue = SetDefaultPrinterW(pwszPrinter);
771 
772 Cleanup:
773  if (pwszPrinter)
774  HeapFree(hProcessHeap, 0, pwszPrinter);
775 
776  return bReturnValue;
777 }
778 
779 BOOL WINAPI
781 {
782  const WCHAR wszDevicesKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
783 
784  DWORD cbDeviceValueData;
785  DWORD cbPrinterValueData = 0;
786  DWORD cchPrinter;
787  DWORD dwErrorCode;
788  HKEY hDevicesKey = NULL;
789  HKEY hWindowsKey = NULL;
790  PWSTR pwszDeviceValueData = NULL;
791  WCHAR wszPrinter[MAX_PRINTER_NAME + 1];
792 
793  TRACE("SetDefaultPrinterW(%S)\n", pszPrinter);
794 
795  // Open the Devices registry key.
796  dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszDevicesKey, 0, KEY_READ, &hDevicesKey);
797  if (dwErrorCode != ERROR_SUCCESS)
798  {
799  ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
800  goto Cleanup;
801  }
802 
803  // Did the caller give us a printer to set as default?
804  if (pszPrinter && *pszPrinter)
805  {
806  // Check if the given printer exists and query the value data size.
807  dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, NULL, &cbPrinterValueData);
808  if (dwErrorCode == ERROR_FILE_NOT_FOUND)
809  {
810  dwErrorCode = ERROR_INVALID_PRINTER_NAME;
811  goto Cleanup;
812  }
813  else if (dwErrorCode != ERROR_SUCCESS)
814  {
815  ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
816  goto Cleanup;
817  }
818 
819  cchPrinter = wcslen(pszPrinter);
820  }
821  else
822  {
823  // If there is already a default printer, we're done!
824  cchPrinter = _countof(wszPrinter);
825  if (GetDefaultPrinterW(wszPrinter, &cchPrinter))
826  {
827  dwErrorCode = ERROR_SUCCESS;
828  goto Cleanup;
829  }
830 
831  // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size.
832  cchPrinter = _countof(wszPrinter);
833  dwErrorCode = (DWORD)RegEnumValueW(hDevicesKey, 0, wszPrinter, &cchPrinter, NULL, NULL, NULL, &cbPrinterValueData);
834  if (dwErrorCode != ERROR_MORE_DATA)
835  goto Cleanup;
836 
837  pszPrinter = wszPrinter;
838  }
839 
840  // We now need to query the value data, which has the format "winspool,<Port>:"
841  // and make "<Printer Name>,winspool,<Port>:" out of it.
842  // Allocate a buffer large enough for the final data.
843  cbDeviceValueData = (cchPrinter + 1) * sizeof(WCHAR) + cbPrinterValueData;
844  pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData);
845  if (!pwszDeviceValueData)
846  {
847  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
848  ERR("HeapAlloc failed!\n");
849  goto Cleanup;
850  }
851 
852  // Copy the Printer Name and a comma into it.
853  CopyMemory(pwszDeviceValueData, pszPrinter, cchPrinter * sizeof(WCHAR));
854  pwszDeviceValueData[cchPrinter] = L',';
855 
856  // Append the value data, which has the format "winspool,<Port>:"
857  dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, (PBYTE)&pwszDeviceValueData[cchPrinter + 1], &cbPrinterValueData);
858  if (dwErrorCode != ERROR_SUCCESS)
859  goto Cleanup;
860 
861  // Open the Windows registry key.
862  dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_SET_VALUE, &hWindowsKey);
863  if (dwErrorCode != ERROR_SUCCESS)
864  {
865  ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
866  goto Cleanup;
867  }
868 
869  // Store our new default printer.
870  dwErrorCode = (DWORD)RegSetValueExW(hWindowsKey, wszDeviceValue, 0, REG_SZ, (PBYTE)pwszDeviceValueData, cbDeviceValueData);
871  if (dwErrorCode != ERROR_SUCCESS)
872  {
873  ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode);
874  goto Cleanup;
875  }
876 
877 Cleanup:
878  if (hDevicesKey)
879  RegCloseKey(hDevicesKey);
880 
881  if (hWindowsKey)
882  RegCloseKey(hWindowsKey);
883 
884  if (pwszDeviceValueData)
885  HeapFree(hProcessHeap, 0, pwszDeviceValueData);
886 
887  SetLastError(dwErrorCode);
888  return (dwErrorCode == ERROR_SUCCESS);
889 }
890 
891 BOOL WINAPI
893 {
894  TRACE("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
896  return FALSE;
897 }
898 
899 BOOL WINAPI
901 {
902  TRACE("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
904  return FALSE;
905 }
906 
909 {
910  DOC_INFO_1W wDocInfo1 = { 0 };
911  DWORD cch;
912  DWORD dwErrorCode;
913  DWORD dwReturnValue = 0;
914  PDOC_INFO_1A pDocInfo1 = (PDOC_INFO_1A)pDocInfo;
915 
916  TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
917 
918  // Only check the minimum required for accessing pDocInfo.
919  // Additional sanity checks are done in StartDocPrinterW.
920  if (!pDocInfo1)
921  {
922  dwErrorCode = ERROR_INVALID_PARAMETER;
923  goto Cleanup;
924  }
925 
926  if (Level != 1)
927  {
928  dwErrorCode = ERROR_INVALID_LEVEL;
929  goto Cleanup;
930  }
931 
932  if (pDocInfo1->pDatatype)
933  {
934  // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
935  cch = strlen(pDocInfo1->pDatatype);
936 
937  wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
938  if (!wDocInfo1.pDatatype)
939  {
940  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
941  ERR("HeapAlloc failed!\n");
942  goto Cleanup;
943  }
944 
945  MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDatatype, -1, wDocInfo1.pDatatype, cch + 1);
946  }
947 
948  if (pDocInfo1->pDocName)
949  {
950  // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
951  cch = strlen(pDocInfo1->pDocName);
952 
953  wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
954  if (!wDocInfo1.pDocName)
955  {
956  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
957  ERR("HeapAlloc failed!\n");
958  goto Cleanup;
959  }
960 
961  MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDocName, -1, wDocInfo1.pDocName, cch + 1);
962  }
963 
964  if (pDocInfo1->pOutputFile)
965  {
966  // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
967  cch = strlen(pDocInfo1->pOutputFile);
968 
969  wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
970  if (!wDocInfo1.pOutputFile)
971  {
972  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
973  ERR("HeapAlloc failed!\n");
974  goto Cleanup;
975  }
976 
977  MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pOutputFile, -1, wDocInfo1.pOutputFile, cch + 1);
978  }
979 
980  dwReturnValue = StartDocPrinterW(hPrinter, Level, (PBYTE)&wDocInfo1);
981  dwErrorCode = GetLastError();
982 
983 Cleanup:
984  if (wDocInfo1.pDatatype)
985  HeapFree(hProcessHeap, 0, wDocInfo1.pDatatype);
986 
987  if (wDocInfo1.pDocName)
988  HeapFree(hProcessHeap, 0, wDocInfo1.pDocName);
989 
990  if (wDocInfo1.pOutputFile)
991  HeapFree(hProcessHeap, 0, wDocInfo1.pOutputFile);
992 
993  SetLastError(dwErrorCode);
994  return dwReturnValue;
995 }
996 
999 {
1000  DWORD cbAddJobInfo1;
1001  DWORD cbNeeded;
1002  DWORD dwErrorCode;
1003  DWORD dwReturnValue = 0;
1004  PADDJOB_INFO_1W pAddJobInfo1 = NULL;
1005  PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
1006  PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1007 
1008  TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
1009 
1010  // Sanity checks.
1011  if (!pHandle)
1012  {
1013  dwErrorCode = ERROR_INVALID_HANDLE;
1014  goto Cleanup;
1015  }
1016 
1017  if (!pDocInfo1)
1018  {
1019  dwErrorCode = ERROR_INVALID_PARAMETER;
1020  goto Cleanup;
1021  }
1022 
1023  if (Level != 1)
1024  {
1025  dwErrorCode = ERROR_INVALID_LEVEL;
1026  goto Cleanup;
1027  }
1028 
1029  if (pHandle->bStartedDoc)
1030  {
1031  dwErrorCode = ERROR_INVALID_PRINTER_STATE;
1032  goto Cleanup;
1033  }
1034 
1035  // Check if we want to redirect output into a file.
1036  if (pDocInfo1->pOutputFile)
1037  {
1038  // Do a StartDocPrinter RPC call in this case.
1039  dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
1040  }
1041  else
1042  {
1043  // Allocate memory for the ADDJOB_INFO_1W structure and a path.
1044  cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR);
1045  pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1);
1046  if (!pAddJobInfo1)
1047  {
1048  dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1049  ERR("HeapAlloc failed!\n");
1050  goto Cleanup;
1051  }
1052 
1053  // Try to add a new job.
1054  // This only succeeds if the printer is set to do spooled printing.
1055  if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded))
1056  {
1057  // Do spooled printing.
1058  dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1);
1059  }
1060  else if (GetLastError() == ERROR_INVALID_ACCESS)
1061  {
1062  // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
1063  // In this case, we do a StartDocPrinter RPC call.
1064  dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
1065  }
1066  else
1067  {
1068  dwErrorCode = GetLastError();
1069  ERR("AddJobW failed with error %lu!\n", dwErrorCode);
1070  goto Cleanup;
1071  }
1072  }
1073 
1074  if (dwErrorCode == ERROR_SUCCESS)
1075  {
1076  pHandle->bStartedDoc = TRUE;
1077  dwReturnValue = pHandle->dwJobID;
1078  }
1079 
1080 Cleanup:
1081  if (pAddJobInfo1)
1082  HeapFree(hProcessHeap, 0, pAddJobInfo1);
1083 
1084  SetLastError(dwErrorCode);
1085  return dwReturnValue;
1086 }
1087 
1088 BOOL WINAPI
1090 {
1091  DWORD dwErrorCode;
1092  PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1093 
1094  TRACE("StartPagePrinter(%p)\n", hPrinter);
1095 
1096  // Sanity checks.
1097  if (!pHandle)
1098  {
1099  dwErrorCode = ERROR_INVALID_HANDLE;
1100  goto Cleanup;
1101  }
1102 
1103  // Do the RPC call
1104  RpcTryExcept
1105  {
1106  dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter);
1107  }
1109  {
1110  dwErrorCode = RpcExceptionCode();
1111  ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode);
1112  }
1113  RpcEndExcept;
1114 
1115 Cleanup:
1116  SetLastError(dwErrorCode);
1117  return (dwErrorCode == ERROR_SUCCESS);
1118 }
1119 
1120 BOOL WINAPI
1121 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
1122 {
1123  DWORD dwErrorCode;
1124  PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1125 
1126  TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
1127 
1128  // Sanity checks.
1129  if (!pHandle)
1130  {
1131  dwErrorCode = ERROR_INVALID_HANDLE;
1132  goto Cleanup;
1133  }
1134 
1135  if (!pHandle->bStartedDoc)
1136  {
1137  dwErrorCode = ERROR_SPL_NO_STARTDOC;
1138  goto Cleanup;
1139  }
1140 
1141  if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
1142  {
1143  // Write to the spool file. This doesn't need an RPC request.
1144  if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL))
1145  {
1146  dwErrorCode = GetLastError();
1147  ERR("WriteFile failed with error %lu!\n", dwErrorCode);
1148  goto Cleanup;
1149  }
1150 
1151  dwErrorCode = ERROR_SUCCESS;
1152  }
1153  else
1154  {
1155  // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
1156  // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
1157 
1158  // Do the RPC call
1159  RpcTryExcept
1160  {
1161  dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
1162  }
1164  {
1165  dwErrorCode = RpcExceptionCode();
1166  ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode);
1167  }
1168  RpcEndExcept;
1169  }
1170 
1171 Cleanup:
1172  SetLastError(dwErrorCode);
1173  return (dwErrorCode == ERROR_SUCCESS);
1174 }
1175 
1176 BOOL WINAPI
1177 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
1178 {
1179  TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
1180  return FALSE;
1181 }
DWORD *typedef PVOID
Definition: winlogon.h:61
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
BOOL WINAPI EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
Definition: printers.c:66
DWORD _RpcStartPagePrinter(WINSPOOL_PRINTER_HANDLE hPrinter)
Definition: printers.c:267
LPWSTR pDocName
Definition: winspool.h:556
BOOL WINAPI ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
Definition: printers.c:207
#define RpcEndExcept
Definition: rpc.h:128
unsigned short WORD
Definition: ntddk_ex.h:93
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
#define ERROR_SUCCESS
Definition: deptool.c:10
union _WINSPOOL_DOC_INFO_CONTAINER::@3272 DocInfo
#define WideCharToMultiByte
Definition: compat.h:101
#define KEY_SET_VALUE
Definition: nt_native.h:1017
BOOL WINAPI GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
Definition: printers.c:507
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
#define KEY_READ
Definition: nt_native.h:1023
__wchar_t WCHAR
Definition: xmlstorage.h:180
DWORD _RpcEndDocPrinter(WINSPOOL_PRINTER_HANDLE hPrinter)
Definition: printers.c:61
BOOL WINAPI SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
Definition: printers.c:900
#define CP_ACP
Definition: compat.h:99
#define _countof(array)
Definition: fontsub.cpp:30
DWORD WINAPI DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW *pDevMode)
Definition: printers.c:188
#define HKEY_CURRENT_USER
Definition: winreg.h:11
unsigned char * LPBYTE
Definition: typedefs.h:52
WINBOOL WINAPI GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD cbBuf, LPDWORD pcbNeeded)
#define ERROR_INVALID_HANDLE
Definition: compat.h:88
LPWSTR pOutputFile
Definition: winspool.h:557
BOOL WINAPI GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
Definition: printers.c:363
HWND hWnd
Definition: settings.c:17
PVOID *typedef PWSTR
Definition: winlogon.h:66
struct _ADDJOB_INFO_1W ADDJOB_INFO_1W
HANDLE HWND
Definition: compat.h:13
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
DWORD _RpcEnumPrinters(DWORD Flags, WINSPOOL_HANDLE Name, DWORD Level, BYTE *pPrinterEnum, DWORD cbBuf, DWORD *pcbNeeded, DWORD *pcReturned)
Definition: printers.c:99
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define ZeroMemory
Definition: winbase.h:1635
DWORD WINAPI StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
Definition: printers.c:222
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:55
Definition: shell.h:41
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
char * LPSTR
Definition: xmlstorage.h:182
DEVMODEW *WINAPI GdiConvertToDevmodeW(const DEVMODEA *)
Definition: misc.c:968
#define DWORD
Definition: msvc.h:34
BOOL bStartedDoc
Definition: precomp.h:32
BOOL WINAPI ResetPrinterA(HANDLE hPrinter, PPRINTER_DEFAULTSA pDefault)
Definition: printers.c:730
DWORD dwJobID
Definition: precomp.h:33
BOOL WINAPI DeletePrinter(HANDLE hPrinter)
Definition: printers.c:172
DWORD DWORD
Definition: winlogon.h:84
#define FILE_SHARE_READ
Definition: compat.h:125
LONG WINAPI DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
Definition: printers.c:204
LPDEVMODEW pDevMode
Definition: winspool.h:769
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
DWORD _RpcStartDocPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, WINSPOOL_DOC_INFO_CONTAINER *pDocInfoContainer, DWORD *pJobId)
Definition: printers.c:248
LPCRECT BOOL fMode
Definition: msvc.h:58
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
#define FALSE
Definition: types.h:117
BOOL WINAPI GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
Definition: printers.c:409
long LONG
Definition: pedump.c:60
BOOL WINAPI AbortPrinter(HANDLE hPrinter)
Definition: printers.c:109
#define GENERIC_WRITE
Definition: nt_native.h:90
#define RpcTryExcept
Definition: rpc.h:126
DWORD _RpcEndPagePrinter(WINSPOOL_PRINTER_HANDLE hPrinter)
Definition: printers.c:80
#define ERROR_SPL_NO_STARTDOC
Definition: winerror.h:1208
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
LONG WINAPI RegEnumValueW(_In_ HKEY hKey, _In_ DWORD index, _Out_ LPWSTR value, _Inout_ PDWORD val_count, _Reserved_ PDWORD reserved, _Out_opt_ PDWORD type, _Out_opt_ LPBYTE data, _Inout_opt_ PDWORD count)
Definition: reg.c:2867
BOOL WINAPI ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault)
Definition: printers.c:738
static DWORD DWORD void LPSTR DWORD cch
Definition: str.c:201
smooth NULL
Definition: ftsmooth.c:416
BOOL WINAPI GetPrinterDriverW(HANDLE hPrinter, PWSTR pEnvironment, DWORD Level, PBYTE pDriverInfo, DWORD cbBuf, PDWORD pcbNeeded)
Definition: printers.c:125
static DWORD _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1)
Definition: printers.c:86
const char * LPCSTR
Definition: xmlstorage.h:183
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
BOOL WINAPI WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
Definition: printers.c:252
BOOL WINAPI GetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD cbBuf, PDWORD pcbNeeded)
Definition: printers.c:140
HANDLE hSPLFile
Definition: precomp.h:35
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
LONG WINAPI RegSetValueExW(_In_ HKEY hKey, _In_ LPCWSTR lpValueName, _In_ DWORD Reserved, _In_ DWORD dwType, _In_ CONST BYTE *lpData, _In_ DWORD cbData)
Definition: reg.c:4917
BOOL WINAPI ClosePrinter(HANDLE hPrinter)
Definition: printers.c:12
#define RpcExceptionCode()
Definition: rpc.h:132
#define TRACE(s)
Definition: solgame.cpp:4
static LPSTR pName
Definition: security.c:75
unsigned int BOOL
Definition: ntddk_ex.h:94
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4134
LPWSTR pDatatype
Definition: winspool.h:558
HANDLE HKEY
Definition: registry.h:24
LPDEVMODEA pDevMode
Definition: winspool.h:763
DWORD _RpcScheduleJob(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD JobId)
Definition: jobs.c:110
BOOL WINAPI FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep)
Definition: printers.c:355
#define MAX_PATH
Definition: compat.h:26
DWORD _RpcWritePrinter(WINSPOOL_PRINTER_HANDLE hPrinter, BYTE *pBuf, DWORD cbBuf, DWORD *pcWritten)
Definition: printers.c:286
#define CopyMemory
Definition: winbase.h:1633
ACCESS_MASK DesiredAccess
Definition: winspool.h:770
#define SetLastError(x)
Definition: compat.h:409
DWORD _RpcReadPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, BYTE *pBuf, DWORD cbBuf, DWORD *pcNoBytesRead)
Definition: printers.c:201
#define MAX_PRINTER_NAME
Definition: fpSetJob.c:25
_In_ PUNICODE_STRING Name
Definition: mrx.h:218
static const WCHAR wszWindowsKey[]
Definition: printers.c:15
LPSTR pOutputFile
Definition: winspool.h:551
static const WCHAR L[]
Definition: oid.c:1087
LPSTR pDatatype
Definition: winspool.h:552
BOOL WINAPI OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
Definition: printers.c:570
BOOL WINAPI SetPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
Definition: printers.c:892
BOOL WINAPI EndPagePrinter(HANDLE hPrinter)
Definition: printers.c:51
#define ERROR_INVALID_ACCESS
Definition: winerror.h:115
DWORD _RpcOpenPrinter(WINSPOOL_HANDLE pPrinterName, WINSPOOL_PRINTER_HANDLE *phPrinter, WCHAR *pDatatype, WINSPOOL_DEVMODE_CONTAINER *pDevModeContainer, DWORD AccessRequired)
Definition: printers.c:170
WINSPOOL_DOC_INFO_1 * pDocInfo1
Definition: winspool.idl:577
BOOL WINAPI XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
Definition: printers.c:267
static const WCHAR Cleanup[]
Definition: register.c:80
#define ERROR_MORE_DATA
Definition: dderror.h:13
#define WINAPI
Definition: msvc.h:20
#define ERROR_INVALID_PRINTER_NAME
Definition: winerror.h:1108
unsigned char BYTE
Definition: ntddk_ex.h:96
BOOL WINAPI MarshallUpStructure(DWORD cbSize, PVOID pStructure, const MARSHALLING_INFO *pInfo, DWORD cbStructureSize, BOOL bSomeBoolean)
Definition: marshalling.c:137
HANDLE WINAPI AddPrinterA(PSTR pName, DWORD Level, PBYTE pPrinter)
Definition: printers.c:117
#define ERR(fmt,...)
Definition: debug.h:109
DWORD WINAPI DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA *pDevMode)
Definition: printers.c:180
HANDLE WINAPI AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter)
Definition: printers.c:125
#define CREATE_ALWAYS
Definition: disk.h:72
DWORD *typedef HANDLE
Definition: winlogon.h:61
static const MARSHALLING * pPrinterInfoMarshalling[]
Definition: printers.h:146
_In_ DWORD _Out_ PDWORD pcbNeeded
Definition: winddi.h:3827
BOOL WINAPI EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
Definition: printers.c:307
signed char * PSTR
Definition: retypes.h:7
BOOL WINAPI StartPagePrinter(HANDLE hPrinter)
Definition: printers.c:237
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
BOOL WINAPI EndDocPrinter(HANDLE hPrinter)
Definition: printers.c:36
DWORD * PDWORD
Definition: pedump.c:68
#define MultiByteToWideChar
Definition: compat.h:100
DWORD _RpcClosePrinter(WINSPOOL_PRINTER_HANDLE *phPrinter)
Definition: printers.c:33
BOOL WINAPI OpenPrinterW(PWSTR pPrinterName, PHANDLE phPrinter, PPRINTER_DEFAULTSW pDefault)
Definition: printers.c:155
#define CreateFileW
Definition: compat.h:400
BOOL WINAPI SetDefaultPrinterA(LPCSTR pszPrinter)
Definition: printers.c:746
static const WCHAR wszDeviceValue[]
Definition: printers.c:16
BOOL WINAPI GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
Definition: printers.c:500
WINBOOL WINAPI AddJobW(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
struct _DOC_INFO_1W * PDOC_INFO_1W
HANDLE * LPHANDLE
Definition: windef.h:242
uint32_t * LPDWORD
Definition: typedefs.h:57
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3381
#define UNIMPLEMENTED
Definition: debug.h:114
LONG WINAPI DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
Definition: printers.c:196
#define ERROR_INVALID_NAME
Definition: compat.h:93
ACCESS_MASK DesiredAccess
Definition: winspool.h:764
struct _devicemodeW DEVMODEW
static HANDLE hXcv
Definition: localmon.c:61
const uint16_t * PCWSTR
Definition: typedefs.h:55
#define ERROR_INVALID_PRINTER_STATE
Definition: winerror.h:1148
#define ERROR_INVALID_LEVEL
Definition: winerror.h:196
WCHAR * LPWSTR
Definition: xmlstorage.h:184
struct _DOC_INFO_1A * PDOC_INFO_1A
WINBOOL WINAPI SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pJob, DWORD Command)
LPSTR pDocName
Definition: winspool.h:550
BYTE * PBYTE
Definition: pedump.c:66
struct _SPOOLER_HANDLE * PSPOOLER_HANDLE
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define HeapFree(x, y, z)
Definition: compat.h:394
ULONG ACCESS_MASK
Definition: nt_native.h:40
DWORD _RpcGetPrinter(WINSPOOL_PRINTER_HANDLE hPrinter, DWORD Level, BYTE *pPrinter, DWORD cbBuf, DWORD *pcbNeeded)
Definition: printers.c:138
static DWORD _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB_INFO_1W pAddJobInfo1)
Definition: printers.c:19
BOOL WINAPI SetDefaultPrinterW(LPCWSTR pszPrinter)
Definition: printers.c:780
#define RpcExcept(expr)
Definition: rpc.h:127
BOOL WINAPI MarshallUpStructuresArray(DWORD cbSize, PVOID pStructuresArray, DWORD cElements, const MARSHALLING_INFO *pInfo, DWORD cbStructureSize, BOOL bSomeBoolean)
Definition: marshalling.c:202
HANDLE hProcessHeap
Definition: kbswitch.c:25
DWORD WINAPI StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
Definition: printers.c:908
HANDLE hPrinter
Definition: precomp.h:34
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
#define REG_SZ
Definition: layer.c:22