a34a43fa60e5f7ac079f9bbd3338ff4e21fa33aa
[reactos.git] / reactos / win32ss / printing / base / winspool / printers.c
1 /*
2 * PROJECT: ReactOS Spooler API
3 * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software Foundation
4 * PURPOSE: Functions related to Printers and printing
5 * COPYRIGHT: Copyright 2015-2017 Colin Finck <colin@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 static void
11 _MarshallUpPrinterInfo(PBYTE* ppPrinterInfo, DWORD Level)
12 {
13 // Replace relative offset addresses in the output by absolute pointers and advance to the next structure.
14 if (Level == 0)
15 {
16 PPRINTER_INFO_STRESS pPrinterInfo0 = (PPRINTER_INFO_STRESS)(*ppPrinterInfo);
17
18 pPrinterInfo0->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo0->pPrinterName + (ULONG_PTR)pPrinterInfo0);
19
20 if (pPrinterInfo0->pServerName)
21 pPrinterInfo0->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo0->pServerName + (ULONG_PTR)pPrinterInfo0);
22
23 *ppPrinterInfo += sizeof(PRINTER_INFO_STRESS);
24 }
25 else if (Level == 1)
26 {
27 PPRINTER_INFO_1W pPrinterInfo1 = (PPRINTER_INFO_1W)(*ppPrinterInfo);
28
29 pPrinterInfo1->pName = (PWSTR)((ULONG_PTR)pPrinterInfo1->pName + (ULONG_PTR)pPrinterInfo1);
30 pPrinterInfo1->pDescription = (PWSTR)((ULONG_PTR)pPrinterInfo1->pDescription + (ULONG_PTR)pPrinterInfo1);
31 pPrinterInfo1->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo1->pComment + (ULONG_PTR)pPrinterInfo1);
32
33 *ppPrinterInfo += sizeof(PRINTER_INFO_1W);
34 }
35 else if (Level == 2)
36 {
37 PPRINTER_INFO_2W pPrinterInfo2 = (PPRINTER_INFO_2W)(*ppPrinterInfo);
38
39 pPrinterInfo2->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrinterName + (ULONG_PTR)pPrinterInfo2);
40 pPrinterInfo2->pShareName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pShareName + (ULONG_PTR)pPrinterInfo2);
41 pPrinterInfo2->pPortName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPortName + (ULONG_PTR)pPrinterInfo2);
42 pPrinterInfo2->pDriverName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pDriverName + (ULONG_PTR)pPrinterInfo2);
43 pPrinterInfo2->pComment = (PWSTR)((ULONG_PTR)pPrinterInfo2->pComment + (ULONG_PTR)pPrinterInfo2);
44 pPrinterInfo2->pLocation = (PWSTR)((ULONG_PTR)pPrinterInfo2->pLocation + (ULONG_PTR)pPrinterInfo2);
45 pPrinterInfo2->pDevMode = (PDEVMODEW)((ULONG_PTR)pPrinterInfo2->pDevMode + (ULONG_PTR)pPrinterInfo2);
46 pPrinterInfo2->pSepFile = (PWSTR)((ULONG_PTR)pPrinterInfo2->pSepFile + (ULONG_PTR)pPrinterInfo2);
47 pPrinterInfo2->pPrintProcessor = (PWSTR)((ULONG_PTR)pPrinterInfo2->pPrintProcessor + (ULONG_PTR)pPrinterInfo2);
48 pPrinterInfo2->pDatatype = (PWSTR)((ULONG_PTR)pPrinterInfo2->pDatatype + (ULONG_PTR)pPrinterInfo2);
49 pPrinterInfo2->pParameters = (PWSTR)((ULONG_PTR)pPrinterInfo2->pParameters + (ULONG_PTR)pPrinterInfo2);
50
51 if (pPrinterInfo2->pServerName)
52 pPrinterInfo2->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo2->pServerName + (ULONG_PTR)pPrinterInfo2);
53
54 if (pPrinterInfo2->pSecurityDescriptor)
55 pPrinterInfo2->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)((ULONG_PTR)pPrinterInfo2->pSecurityDescriptor + (ULONG_PTR)pPrinterInfo2);
56
57 *ppPrinterInfo += sizeof(PRINTER_INFO_2W);
58 }
59 else if (Level == 3)
60 {
61 PPRINTER_INFO_3 pPrinterInfo3 = (PPRINTER_INFO_3)(*ppPrinterInfo);
62
63 pPrinterInfo3->pSecurityDescriptor = (PSECURITY_DESCRIPTOR)((ULONG_PTR)pPrinterInfo3->pSecurityDescriptor + (ULONG_PTR)pPrinterInfo3);
64
65 *ppPrinterInfo += sizeof(PRINTER_INFO_3);
66 }
67 else if (Level == 4)
68 {
69 PPRINTER_INFO_4W pPrinterInfo4 = (PPRINTER_INFO_4W)(*ppPrinterInfo);
70
71 pPrinterInfo4->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo4->pPrinterName + (ULONG_PTR)pPrinterInfo4);
72
73 if (pPrinterInfo4->pServerName)
74 pPrinterInfo4->pServerName = (PWSTR)((ULONG_PTR)pPrinterInfo4->pServerName + (ULONG_PTR)pPrinterInfo4);
75
76 *ppPrinterInfo += sizeof(PRINTER_INFO_4W);
77 }
78 else if (Level == 5)
79 {
80 PPRINTER_INFO_5W pPrinterInfo5 = (PPRINTER_INFO_5W)(*ppPrinterInfo);
81
82 pPrinterInfo5->pPrinterName = (PWSTR)((ULONG_PTR)pPrinterInfo5->pPrinterName + (ULONG_PTR)pPrinterInfo5);
83 pPrinterInfo5->pPortName = (PWSTR)((ULONG_PTR)pPrinterInfo5->pPortName + (ULONG_PTR)pPrinterInfo5);
84
85 *ppPrinterInfo += sizeof(PRINTER_INFO_5W);
86 }
87 else if (Level == 6)
88 {
89 *ppPrinterInfo += sizeof(PRINTER_INFO_6);
90 }
91 else if (Level == 7)
92 {
93 PPRINTER_INFO_7W pPrinterInfo7 = (PPRINTER_INFO_7W)(*ppPrinterInfo);
94
95 if (pPrinterInfo7->pszObjectGUID)
96 pPrinterInfo7->pszObjectGUID = (PWSTR)((ULONG_PTR)pPrinterInfo7->pszObjectGUID + (ULONG_PTR)pPrinterInfo7);
97
98 *ppPrinterInfo += sizeof(PRINTER_INFO_7W);
99 }
100 else if (Level == 8)
101 {
102 PPRINTER_INFO_8W pPrinterInfo8 = (PPRINTER_INFO_8W)(*ppPrinterInfo);
103
104 pPrinterInfo8->pDevMode = (PDEVMODEW)((ULONG_PTR)pPrinterInfo8->pDevMode + (ULONG_PTR)pPrinterInfo8);
105
106 *ppPrinterInfo += sizeof(PRINTER_INFO_8W);
107 }
108 else if (Level == 9)
109 {
110 PPRINTER_INFO_9W pPrinterInfo9 = (PPRINTER_INFO_9W)(*ppPrinterInfo);
111
112 pPrinterInfo9->pDevMode = (PDEVMODEW)((ULONG_PTR)pPrinterInfo9->pDevMode + (ULONG_PTR)pPrinterInfo9);
113
114 *ppPrinterInfo += sizeof(PRINTER_INFO_9W);
115 }
116 }
117
118 static DWORD
119 _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB_INFO_1W pAddJobInfo1)
120 {
121 DWORD cbNeeded;
122 DWORD dwErrorCode;
123 PJOB_INFO_1W pJobInfo1 = NULL;
124
125 // Create the spool file.
126 pHandle->hSPLFile = CreateFileW(pAddJobInfo1->Path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
127 if (pHandle->hSPLFile == INVALID_HANDLE_VALUE)
128 {
129 dwErrorCode = GetLastError();
130 ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1->Path, dwErrorCode);
131 goto Cleanup;
132 }
133
134 // Get the size of the job information.
135 GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded);
136 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
137 {
138 dwErrorCode = GetLastError();
139 ERR("GetJobW failed with error %lu!\n", dwErrorCode);
140 goto Cleanup;
141 }
142
143 // Allocate enough memory for the returned job information.
144 pJobInfo1 = HeapAlloc(hProcessHeap, 0, cbNeeded);
145 if (!pJobInfo1)
146 {
147 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
148 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
149 goto Cleanup;
150 }
151
152 // Get the job information.
153 if (!GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, cbNeeded, &cbNeeded))
154 {
155 dwErrorCode = GetLastError();
156 ERR("GetJobW failed with error %lu!\n", dwErrorCode);
157 goto Cleanup;
158 }
159
160 // Add our document information.
161 if (pDocInfo1->pDatatype)
162 pJobInfo1->pDatatype = pDocInfo1->pDatatype;
163
164 pJobInfo1->pDocument = pDocInfo1->pDocName;
165
166 // Set the new job information.
167 if (!SetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0))
168 {
169 dwErrorCode = GetLastError();
170 ERR("SetJobW failed with error %lu!\n", dwErrorCode);
171 goto Cleanup;
172 }
173
174 // We were successful!
175 pHandle->dwJobID = pAddJobInfo1->JobId;
176 dwErrorCode = ERROR_SUCCESS;
177
178 Cleanup:
179 if (pJobInfo1)
180 HeapFree(hProcessHeap, 0, pJobInfo1);
181
182 return dwErrorCode;
183 }
184
185 static DWORD
186 _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1)
187 {
188 DWORD dwErrorCode;
189 WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer;
190
191 DocInfoContainer.Level = 1;
192 DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1;
193
194 RpcTryExcept
195 {
196 dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer, &pHandle->dwJobID);
197 }
198 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
199 {
200 dwErrorCode = RpcExceptionCode();
201 ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode);
202 }
203 RpcEndExcept;
204
205 return dwErrorCode;
206 }
207
208 HANDLE WINAPI
209 AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter)
210 {
211 UNIMPLEMENTED;
212 return NULL;
213 }
214
215 BOOL WINAPI
216 ClosePrinter(HANDLE hPrinter)
217 {
218 DWORD dwErrorCode;
219 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
220
221 // Sanity checks.
222 if (!pHandle)
223 {
224 dwErrorCode = ERROR_INVALID_HANDLE;
225 goto Cleanup;
226 }
227
228 // Do the RPC call.
229 RpcTryExcept
230 {
231 dwErrorCode = _RpcClosePrinter(pHandle->hPrinter);
232 }
233 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
234 {
235 dwErrorCode = RpcExceptionCode();
236 ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode);
237 }
238 RpcEndExcept;
239
240 // Close any open file handle.
241 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
242 CloseHandle(pHandle->hSPLFile);
243
244 // Free the memory for the handle.
245 HeapFree(hProcessHeap, 0, pHandle);
246
247 Cleanup:
248 SetLastError(dwErrorCode);
249 return (dwErrorCode == ERROR_SUCCESS);
250
251 }
252
253 DWORD WINAPI
254 DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
255 {
256 return 0;
257 }
258
259 DWORD WINAPI
260 DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
261 {
262 return 0;
263 }
264
265 LONG WINAPI
266 DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
267 {
268 return 0;
269 }
270
271 LONG WINAPI
272 DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
273 {
274 return 0;
275 }
276
277 BOOL WINAPI
278 EndDocPrinter(HANDLE hPrinter)
279 {
280 DWORD dwErrorCode;
281 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
282
283 // Sanity checks.
284 if (!pHandle)
285 {
286 dwErrorCode = ERROR_INVALID_HANDLE;
287 goto Cleanup;
288 }
289
290 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
291 {
292 // For spooled jobs, the document is finished by calling _RpcScheduleJob.
293 RpcTryExcept
294 {
295 dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID);
296 }
297 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
298 {
299 dwErrorCode = RpcExceptionCode();
300 ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
301 }
302 RpcEndExcept;
303
304 // Close the spool file handle.
305 CloseHandle(pHandle->hSPLFile);
306 }
307 else
308 {
309 // In all other cases, just call _RpcEndDocPrinter.
310 RpcTryExcept
311 {
312 dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter);
313 }
314 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
315 {
316 dwErrorCode = RpcExceptionCode();
317 ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode);
318 }
319 RpcEndExcept;
320 }
321
322 // A new document can now be started again.
323 pHandle->bStartedDoc = FALSE;
324
325 Cleanup:
326 SetLastError(dwErrorCode);
327 return (dwErrorCode == ERROR_SUCCESS);
328 }
329
330 BOOL WINAPI
331 EndPagePrinter(HANDLE hPrinter)
332 {
333 DWORD dwErrorCode;
334 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
335
336 // Sanity checks.
337 if (!pHandle)
338 {
339 dwErrorCode = ERROR_INVALID_HANDLE;
340 goto Cleanup;
341 }
342
343 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
344 {
345 // For spooled jobs, we don't need to do anything.
346 dwErrorCode = ERROR_SUCCESS;
347 }
348 else
349 {
350 // In all other cases, just call _RpcEndPagePrinter.
351 RpcTryExcept
352 {
353 dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter);
354 }
355 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
356 {
357 dwErrorCode = RpcExceptionCode();
358 ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode);
359 }
360 RpcEndExcept;
361 }
362
363 Cleanup:
364 SetLastError(dwErrorCode);
365 return (dwErrorCode == ERROR_SUCCESS);
366 }
367
368 BOOL WINAPI
369 EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
370 {
371 return FALSE;
372 }
373
374 BOOL WINAPI
375 EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
376 {
377 DWORD dwErrorCode;
378
379 // Dismiss invalid levels already at this point.
380 if (Level == 3 || Level > 5)
381 {
382 dwErrorCode = ERROR_INVALID_LEVEL;
383 goto Cleanup;
384 }
385
386 if (cbBuf && pPrinterEnum)
387 ZeroMemory(pPrinterEnum, cbBuf);
388
389 // Do the RPC call
390 RpcTryExcept
391 {
392 dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
393 }
394 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
395 {
396 dwErrorCode = RpcExceptionCode();
397 ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
398 }
399 RpcEndExcept;
400
401 if (dwErrorCode == ERROR_SUCCESS)
402 {
403 DWORD i;
404 PBYTE p = pPrinterEnum;
405
406 for (i = 0; i < *pcReturned; i++)
407 _MarshallUpPrinterInfo(&p, Level);
408 }
409
410 Cleanup:
411 SetLastError(dwErrorCode);
412 return (dwErrorCode == ERROR_SUCCESS);
413 }
414
415 BOOL WINAPI
416 GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
417 {
418 return FALSE;
419 }
420
421 BOOL WINAPI
422 GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
423 {
424 return FALSE;
425 }
426
427 BOOL WINAPI
428 GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
429 {
430 return FALSE;
431 }
432
433 BOOL WINAPI
434 GetPrinterDriverA(HANDLE hPrinter, LPSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
435 {
436 return FALSE;
437 }
438
439 BOOL WINAPI
440 GetPrinterDriverW(HANDLE hPrinter, LPWSTR pEnvironment, DWORD Level, LPBYTE pDriverInfo, DWORD cbBuf, LPDWORD pcbNeeded)
441 {
442 return FALSE;
443 }
444
445 BOOL WINAPI
446 GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
447 {
448 DWORD dwErrorCode;
449
450 // Dismiss invalid levels already at this point.
451 if (Level > 9)
452 {
453 dwErrorCode = ERROR_INVALID_LEVEL;
454 goto Cleanup;
455 }
456
457 if (cbBuf && pPrinter)
458 ZeroMemory(pPrinter, cbBuf);
459
460 // Do the RPC call
461 RpcTryExcept
462 {
463 dwErrorCode = _RpcGetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
464 }
465 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
466 {
467 dwErrorCode = RpcExceptionCode();
468 ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode);
469 }
470 RpcEndExcept;
471
472 if (dwErrorCode == ERROR_SUCCESS)
473 {
474 PBYTE p = pPrinter;
475 _MarshallUpPrinterInfo(&p, Level);
476 }
477
478 Cleanup:
479 SetLastError(dwErrorCode);
480 return (dwErrorCode == ERROR_SUCCESS);
481 }
482
483 BOOL WINAPI
484 OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
485 {
486 BOOL bReturnValue = FALSE;
487 DWORD cch;
488 PWSTR pwszPrinterName = NULL;
489 PRINTER_DEFAULTSW wDefault = { 0 };
490
491 if (pPrinterName)
492 {
493 // Convert pPrinterName to a Unicode string pwszPrinterName
494 cch = strlen(pPrinterName);
495
496 pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
497 if (!pwszPrinterName)
498 {
499 ERR("HeapAlloc failed for pwszPrinterName with last error %lu!\n", GetLastError());
500 goto Cleanup;
501 }
502
503 MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, cch + 1);
504 }
505
506 if (pDefault)
507 {
508 wDefault.DesiredAccess = pDefault->DesiredAccess;
509
510 if (pDefault->pDatatype)
511 {
512 // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
513 cch = strlen(pDefault->pDatatype);
514
515 wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
516 if (!wDefault.pDatatype)
517 {
518 ERR("HeapAlloc failed for wDefault.pDatatype with last error %lu!\n", GetLastError());
519 goto Cleanup;
520 }
521
522 MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, wDefault.pDatatype, cch + 1);
523 }
524
525 if (pDefault->pDevMode)
526 wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode);
527 }
528
529 bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
530
531 Cleanup:
532 if (wDefault.pDatatype)
533 HeapFree(hProcessHeap, 0, wDefault.pDatatype);
534
535 if (wDefault.pDevMode)
536 HeapFree(hProcessHeap, 0, wDefault.pDevMode);
537
538 if (pwszPrinterName)
539 HeapFree(hProcessHeap, 0, pwszPrinterName);
540
541 return bReturnValue;
542 }
543
544 BOOL WINAPI
545 OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
546 {
547 DWORD dwErrorCode;
548 HANDLE hPrinter;
549 PSPOOLER_HANDLE pHandle;
550 PWSTR pDatatype = NULL;
551 WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 };
552 ACCESS_MASK AccessRequired = 0;
553
554 // Prepare the additional parameters in the format required by _RpcOpenPrinter
555 if (pDefault)
556 {
557 pDatatype = pDefault->pDatatype;
558 DevModeContainer.cbBuf = sizeof(DEVMODEW);
559 DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
560 AccessRequired = pDefault->DesiredAccess;
561 }
562
563 // Do the RPC call
564 RpcTryExcept
565 {
566 dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired);
567 }
568 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
569 {
570 dwErrorCode = RpcExceptionCode();
571 ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
572 }
573 RpcEndExcept;
574
575 if (dwErrorCode == ERROR_SUCCESS)
576 {
577 // Create a new SPOOLER_HANDLE structure.
578 pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
579 if (!pHandle)
580 {
581 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
582 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
583 goto Cleanup;
584 }
585
586 pHandle->hPrinter = hPrinter;
587 pHandle->hSPLFile = INVALID_HANDLE_VALUE;
588
589 // Return it as phPrinter.
590 *phPrinter = (HANDLE)pHandle;
591 }
592
593 Cleanup:
594 SetLastError(dwErrorCode);
595 return (dwErrorCode == ERROR_SUCCESS);
596 }
597
598 BOOL WINAPI
599 ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
600 {
601 DWORD dwErrorCode;
602 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
603
604 // Sanity checks.
605 if (!pHandle)
606 {
607 dwErrorCode = ERROR_INVALID_HANDLE;
608 goto Cleanup;
609 }
610
611 // Do the RPC call
612 RpcTryExcept
613 {
614 dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
615 }
616 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
617 {
618 dwErrorCode = RpcExceptionCode();
619 ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode);
620 }
621 RpcEndExcept;
622
623 Cleanup:
624 SetLastError(dwErrorCode);
625 return (dwErrorCode == ERROR_SUCCESS);
626 }
627
628 BOOL WINAPI
629 ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault)
630 {
631 UNIMPLEMENTED;
632 return FALSE;
633 }
634
635 BOOL WINAPI
636 SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
637 {
638 UNIMPLEMENTED;
639 return FALSE;
640 }
641
642 DWORD WINAPI
643 StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
644 {
645 DOC_INFO_1W wDocInfo1 = { 0 };
646 DWORD cch;
647 DWORD dwErrorCode;
648 DWORD dwReturnValue = 0;
649 PDOC_INFO_1A pDocInfo1 = (PDOC_INFO_1A)pDocInfo;
650
651 // Only check the minimum required for accessing pDocInfo.
652 // Additional sanity checks are done in StartDocPrinterW.
653 if (!pDocInfo1)
654 {
655 dwErrorCode = ERROR_INVALID_PARAMETER;
656 goto Cleanup;
657 }
658
659 if (Level != 1)
660 {
661 dwErrorCode = ERROR_INVALID_LEVEL;
662 goto Cleanup;
663 }
664
665 if (pDocInfo1->pDatatype)
666 {
667 // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
668 cch = strlen(pDocInfo1->pDatatype);
669
670 wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
671 if (!wDocInfo1.pDatatype)
672 {
673 ERR("HeapAlloc failed for wDocInfo1.pDatatype with last error %lu!\n", GetLastError());
674 goto Cleanup;
675 }
676
677 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDatatype, -1, wDocInfo1.pDatatype, cch + 1);
678 }
679
680 if (pDocInfo1->pDocName)
681 {
682 // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
683 cch = strlen(pDocInfo1->pDocName);
684
685 wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
686 if (!wDocInfo1.pDocName)
687 {
688 ERR("HeapAlloc failed for wDocInfo1.pDocName with last error %lu!\n", GetLastError());
689 goto Cleanup;
690 }
691
692 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDocName, -1, wDocInfo1.pDocName, cch + 1);
693 }
694
695 if (pDocInfo1->pOutputFile)
696 {
697 // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
698 cch = strlen(pDocInfo1->pOutputFile);
699
700 wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
701 if (!wDocInfo1.pOutputFile)
702 {
703 ERR("HeapAlloc failed for wDocInfo1.pOutputFile with last error %lu!\n", GetLastError());
704 goto Cleanup;
705 }
706
707 MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pOutputFile, -1, wDocInfo1.pOutputFile, cch + 1);
708 }
709
710 dwReturnValue = StartDocPrinterW(hPrinter, Level, (PBYTE)&wDocInfo1);
711 dwErrorCode = GetLastError();
712
713 Cleanup:
714 if (wDocInfo1.pDatatype)
715 HeapFree(hProcessHeap, 0, wDocInfo1.pDatatype);
716
717 if (wDocInfo1.pDocName)
718 HeapFree(hProcessHeap, 0, wDocInfo1.pDocName);
719
720 if (wDocInfo1.pOutputFile)
721 HeapFree(hProcessHeap, 0, wDocInfo1.pOutputFile);
722
723 SetLastError(dwErrorCode);
724 return dwReturnValue;
725 }
726
727 DWORD WINAPI
728 StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
729 {
730 DWORD cbAddJobInfo1;
731 DWORD cbNeeded;
732 DWORD dwErrorCode;
733 DWORD dwReturnValue = 0;
734 PADDJOB_INFO_1W pAddJobInfo1 = NULL;
735 PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
736 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
737
738 // Sanity checks.
739 if (!pHandle)
740 {
741 dwErrorCode = ERROR_INVALID_HANDLE;
742 goto Cleanup;
743 }
744
745 if (!pDocInfo1)
746 {
747 dwErrorCode = ERROR_INVALID_PARAMETER;
748 goto Cleanup;
749 }
750
751 if (Level != 1)
752 {
753 dwErrorCode = ERROR_INVALID_LEVEL;
754 goto Cleanup;
755 }
756
757 if (pHandle->bStartedDoc)
758 {
759 dwErrorCode = ERROR_INVALID_PRINTER_STATE;
760 goto Cleanup;
761 }
762
763 // Check if we want to redirect output into a file.
764 if (pDocInfo1->pOutputFile)
765 {
766 // Do a StartDocPrinter RPC call in this case.
767 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
768 }
769 else
770 {
771 // Allocate memory for the ADDJOB_INFO_1W structure and a path.
772 cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR);
773 pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1);
774 if (!pAddJobInfo1)
775 {
776 dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
777 ERR("HeapAlloc failed with error %lu!\n", GetLastError());
778 goto Cleanup;
779 }
780
781 // Try to add a new job.
782 // This only succeeds if the printer is set to do spooled printing.
783 if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded))
784 {
785 // Do spooled printing.
786 dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1);
787 }
788 else if (GetLastError() == ERROR_INVALID_ACCESS)
789 {
790 // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
791 // In this case, we do a StartDocPrinter RPC call.
792 dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
793 }
794 else
795 {
796 dwErrorCode = GetLastError();
797 ERR("AddJobW failed with error %lu!\n", dwErrorCode);
798 goto Cleanup;
799 }
800 }
801
802 if (dwErrorCode == ERROR_SUCCESS)
803 {
804 pHandle->bStartedDoc = TRUE;
805 dwReturnValue = pHandle->dwJobID;
806 }
807
808 Cleanup:
809 if (pAddJobInfo1)
810 HeapFree(hProcessHeap, 0, pAddJobInfo1);
811
812 SetLastError(dwErrorCode);
813 return dwReturnValue;
814 }
815
816 BOOL WINAPI
817 StartPagePrinter(HANDLE hPrinter)
818 {
819 DWORD dwErrorCode;
820 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
821
822 // Sanity checks.
823 if (!pHandle)
824 {
825 dwErrorCode = ERROR_INVALID_HANDLE;
826 goto Cleanup;
827 }
828
829 // Do the RPC call
830 RpcTryExcept
831 {
832 dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter);
833 }
834 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
835 {
836 dwErrorCode = RpcExceptionCode();
837 ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode);
838 }
839 RpcEndExcept;
840
841 Cleanup:
842 SetLastError(dwErrorCode);
843 return (dwErrorCode == ERROR_SUCCESS);
844 }
845
846 BOOL WINAPI
847 WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
848 {
849 DWORD dwErrorCode;
850 PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
851
852 // Sanity checks.
853 if (!pHandle)
854 {
855 dwErrorCode = ERROR_INVALID_HANDLE;
856 goto Cleanup;
857 }
858
859 if (!pHandle->bStartedDoc)
860 {
861 dwErrorCode = ERROR_SPL_NO_STARTDOC;
862 goto Cleanup;
863 }
864
865 if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
866 {
867 // Write to the spool file. This doesn't need an RPC request.
868 if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL))
869 {
870 dwErrorCode = GetLastError();
871 ERR("WriteFile failed with error %lu!\n", dwErrorCode);
872 goto Cleanup;
873 }
874
875 dwErrorCode = ERROR_SUCCESS;
876 }
877 else
878 {
879 // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
880 // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
881
882 // Do the RPC call
883 RpcTryExcept
884 {
885 dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
886 }
887 RpcExcept(EXCEPTION_EXECUTE_HANDLER)
888 {
889 dwErrorCode = RpcExceptionCode();
890 ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode);
891 }
892 RpcEndExcept;
893 }
894
895 Cleanup:
896 SetLastError(dwErrorCode);
897 return (dwErrorCode == ERROR_SUCCESS);
898 }
899
900 BOOL WINAPI
901 XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
902 {
903 return FALSE;
904 }